如何使用链表实现 BFS 树算法?
How do I implement a BFS tree algorithm using a linked list?
我正在尝试使用链表输出 BFS 树。但是,我在实现该算法时遇到了麻烦。我对如何将链表图实现到算法中感到困惑。我不太确定如何创建一个由 false 和 true 数组组成的矩阵,然后遍历它以根据所选的子节点找到 false 节点。我应该收到的输出是
0: 1 3
1: 2 4
3:
4:
代码:
class Node:
def __init__(self, value):
self.vertex = value
self.next = None
class AdjGraph:
def __init__(self, data):
self.data = data
self.graph = [None] * self.data
# Add edges
def addEdge(self, vertice, edge):
currNode = self.graph[vertice]
newNode = Node(edge)
if currNode == None:
self.graph[vertice] = newNode
return
while currNode != None:
if currNode.next == None:
currNode.next = newNode
break
currNode = currNode.next
# Implement BFS Graph
def bfs(self, s):
# Set discovered[s] = true, discovered[v] = false for all other v
discovered = [False] * self.graph
discovered[s] = True
# Intialize L[0] to consist of the single element s
layer = []
layer.append(s)
# Set the counter i = 0
i = 0
# Set the current BFS tree T = None
T = None
# While L[i] is not empty
while layer:
# Initialize an empty list L[i+1]
empty_list = layer[i+1]
print (s, end = " ")
# For each node u is an element of L[i]
for u in layer[i]:
# Consider each edge (u, v) incident to u
if discovered[v] == False:
# Set discovered[v] = true
discovered[v] = True
# Add edge (u, v) to the tree T
T.append
# Add v to the list L[i+1]
empty_list.append(v)
# Print the graph
def printGraph(self):
adj_list = "Adjacency List"
for i in range(self.data):
adj_list += "\n\nNode " + str(i) + ": "
temp = self.graph[i]
while temp:
adj_list += str(temp.vertex) + " "
temp = temp.next
print(adj_list)
g = AdjGraph(5)
g.addEdge(0, 1)
g.addEdge(0, 3)
g.addEdge(1, 0)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(2, 1)
g.addEdge(2, 4)
g.addEdge(3, 0)
g.addEdge(3, 1)
g.addEdge(3, 4)
g.addEdge(4, 1)
g.addEdge(4, 2)
g.addEdge(4, 3)
g.bfs(0)
您的 bfs
代码有很多问题。我不会一一列举,但是:
[False] * self.graph
没有意义,因为 self.graph
不是数字
layer[i+1]
第一次求值时不存在
for u in layer[i]
不起作用,因为 layer[i]
是一个节点号 (s
),并且不可迭代
empty_list
收到值,但从未使用过。
T.append
什么都不做。
- 尽管尝试将数据放入
T
,但从未使用过。
i
的值永远不会改变。
bfs
只修改局部变量而不会 return 任何东西。所以在它被调用之后,除了打印的节点号之外,与调用之前没有什么不同。但我想那只是为了调试目的,因为它不遵循输出格式。
正如我在评论中提到的,由于预期输出对应于由广度优先搜索 (BFS) 形成的搜索树,因此根据添加节点的顺序和访问顺序,输出可能会有所不同节点。
示例图如下所示:
0-----1
\ /|\
\ / | \
3--4--2
从节点 0 开始的 BFS 可以生成以下任一搜索树:
0-----1 0-----1
\ |\ \ \
\ | \ \ \
3 4 2 3--4 2
这取决于节点1和节点3展开的顺序。第一棵树是节点1先展开的结果,第二棵树是节点3先展开的结果
现在,既然您想使用链表,我还应该提到 向链表添加 一个节点在 开始时更有效列表的 比最后(除非您还维护 tail 引用)。所以我建议不要使用 currNode
循环,而是 prepend 列表开头的新节点。这样就没有循环了。这当然会影响最终出现在列表中的节点的顺序。
以下代码将从图中删除 BFS 树中未使用的边。这样您就可以使用 printGraph
函数输出结果。
代码:
class Node:
def __init__(self, value, nxt=None):
self.vertex = value
self.next = nxt
class AdjGraph:
def __init__(self, size):
self.size = size
self.graph = [None] * self.size
def addEdge(self, vertex, edge):
# Prepend the new node to the linked list
self.graph[vertex] = Node(edge, self.graph[vertex])
def bfs(self, s):
discovered = [False] * self.size
discovered[s] = True
layer = [s]
while layer:
empty_list = []
for u in layer:
keep = None # this will be the new (filtered) list for self.graph[u]
v = self.graph[u]
while v:
nxt = v.next
if not discovered[v.vertex]:
discovered[v.vertex] = True
empty_list.append(v.vertex)
# Prepend v to the keep linked list
v.next = keep
keep = v
v = nxt
self.graph[u] = keep
layer = empty_list # start working with the next layer
def printGraph(self):
adj_list = "Adjacency List"
for i in range(self.size):
adj_list += "\nNode " + str(i) + ": "
temp = self.graph[i]
while temp:
adj_list += str(temp.vertex) + " "
temp = temp.next
print(adj_list)
g = AdjGraph(5)
g.addEdge(0, 1)
g.addEdge(0, 3)
g.addEdge(1, 0)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(2, 1)
g.addEdge(2, 4)
g.addEdge(3, 0)
g.addEdge(3, 1)
g.addEdge(3, 4)
g.addEdge(4, 1)
g.addEdge(4, 2)
g.addEdge(4, 3)
g.bfs(0)
g.printGraph()
输出:
Adjacency List
Node 0: 1 3
Node 1: 2
Node 2:
Node 3: 4
Node 4:
我正在尝试使用链表输出 BFS 树。但是,我在实现该算法时遇到了麻烦。我对如何将链表图实现到算法中感到困惑。我不太确定如何创建一个由 false 和 true 数组组成的矩阵,然后遍历它以根据所选的子节点找到 false 节点。我应该收到的输出是
0: 1 3
1: 2 4
3:
4:
代码:
class Node:
def __init__(self, value):
self.vertex = value
self.next = None
class AdjGraph:
def __init__(self, data):
self.data = data
self.graph = [None] * self.data
# Add edges
def addEdge(self, vertice, edge):
currNode = self.graph[vertice]
newNode = Node(edge)
if currNode == None:
self.graph[vertice] = newNode
return
while currNode != None:
if currNode.next == None:
currNode.next = newNode
break
currNode = currNode.next
# Implement BFS Graph
def bfs(self, s):
# Set discovered[s] = true, discovered[v] = false for all other v
discovered = [False] * self.graph
discovered[s] = True
# Intialize L[0] to consist of the single element s
layer = []
layer.append(s)
# Set the counter i = 0
i = 0
# Set the current BFS tree T = None
T = None
# While L[i] is not empty
while layer:
# Initialize an empty list L[i+1]
empty_list = layer[i+1]
print (s, end = " ")
# For each node u is an element of L[i]
for u in layer[i]:
# Consider each edge (u, v) incident to u
if discovered[v] == False:
# Set discovered[v] = true
discovered[v] = True
# Add edge (u, v) to the tree T
T.append
# Add v to the list L[i+1]
empty_list.append(v)
# Print the graph
def printGraph(self):
adj_list = "Adjacency List"
for i in range(self.data):
adj_list += "\n\nNode " + str(i) + ": "
temp = self.graph[i]
while temp:
adj_list += str(temp.vertex) + " "
temp = temp.next
print(adj_list)
g = AdjGraph(5)
g.addEdge(0, 1)
g.addEdge(0, 3)
g.addEdge(1, 0)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(2, 1)
g.addEdge(2, 4)
g.addEdge(3, 0)
g.addEdge(3, 1)
g.addEdge(3, 4)
g.addEdge(4, 1)
g.addEdge(4, 2)
g.addEdge(4, 3)
g.bfs(0)
您的 bfs
代码有很多问题。我不会一一列举,但是:
[False] * self.graph
没有意义,因为self.graph
不是数字layer[i+1]
第一次求值时不存在for u in layer[i]
不起作用,因为layer[i]
是一个节点号 (s
),并且不可迭代empty_list
收到值,但从未使用过。T.append
什么都不做。- 尽管尝试将数据放入
T
,但从未使用过。 i
的值永远不会改变。bfs
只修改局部变量而不会 return 任何东西。所以在它被调用之后,除了打印的节点号之外,与调用之前没有什么不同。但我想那只是为了调试目的,因为它不遵循输出格式。
正如我在评论中提到的,由于预期输出对应于由广度优先搜索 (BFS) 形成的搜索树,因此根据添加节点的顺序和访问顺序,输出可能会有所不同节点。
示例图如下所示:
0-----1
\ /|\
\ / | \
3--4--2
从节点 0 开始的 BFS 可以生成以下任一搜索树:
0-----1 0-----1
\ |\ \ \
\ | \ \ \
3 4 2 3--4 2
这取决于节点1和节点3展开的顺序。第一棵树是节点1先展开的结果,第二棵树是节点3先展开的结果
现在,既然您想使用链表,我还应该提到 向链表添加 一个节点在 开始时更有效列表的 比最后(除非您还维护 tail 引用)。所以我建议不要使用 currNode
循环,而是 prepend 列表开头的新节点。这样就没有循环了。这当然会影响最终出现在列表中的节点的顺序。
以下代码将从图中删除 BFS 树中未使用的边。这样您就可以使用 printGraph
函数输出结果。
代码:
class Node:
def __init__(self, value, nxt=None):
self.vertex = value
self.next = nxt
class AdjGraph:
def __init__(self, size):
self.size = size
self.graph = [None] * self.size
def addEdge(self, vertex, edge):
# Prepend the new node to the linked list
self.graph[vertex] = Node(edge, self.graph[vertex])
def bfs(self, s):
discovered = [False] * self.size
discovered[s] = True
layer = [s]
while layer:
empty_list = []
for u in layer:
keep = None # this will be the new (filtered) list for self.graph[u]
v = self.graph[u]
while v:
nxt = v.next
if not discovered[v.vertex]:
discovered[v.vertex] = True
empty_list.append(v.vertex)
# Prepend v to the keep linked list
v.next = keep
keep = v
v = nxt
self.graph[u] = keep
layer = empty_list # start working with the next layer
def printGraph(self):
adj_list = "Adjacency List"
for i in range(self.size):
adj_list += "\nNode " + str(i) + ": "
temp = self.graph[i]
while temp:
adj_list += str(temp.vertex) + " "
temp = temp.next
print(adj_list)
g = AdjGraph(5)
g.addEdge(0, 1)
g.addEdge(0, 3)
g.addEdge(1, 0)
g.addEdge(1, 2)
g.addEdge(1, 3)
g.addEdge(1, 4)
g.addEdge(2, 1)
g.addEdge(2, 4)
g.addEdge(3, 0)
g.addEdge(3, 1)
g.addEdge(3, 4)
g.addEdge(4, 1)
g.addEdge(4, 2)
g.addEdge(4, 3)
g.bfs(0)
g.printGraph()
输出:
Adjacency List
Node 0: 1 3
Node 1: 2
Node 2:
Node 3: 4
Node 4: