【发布时间】:2021-11-26 23:38:30
【问题描述】:
有两种实现 BFS 的方法来找到两个节点之间的最短路径。第一种是使用列表列表来表示路径队列。另一种是维护每个节点到其父节点的映射,在检查相邻节点时,记录其父节点,最后根据父映射进行回溯,找到路径。 (有关详细信息,请参阅此帖子。https://stackoverflow.com/a/8922151/13886907。感谢乔对该问题的回答和代码!)
复制到这里: 第一种方式:
def bfs(graph, start, end):
# maintain a queue of paths
queue = []
# push the first path into the queue
queue.append([start])
while queue:
# get the first path from the queue
path = queue.pop(0)
# get the last node from the path
node = path[-1]
# path found
if node == end:
return path
# enumerate all adjacent nodes, construct a
# new path and push it into the queue
for adjacent in graph.get(node, []):
new_path = list(path)
new_path.append(adjacent)
queue.append(new_path)
print(bfs(graph, 'A', 'F'))
第二种方式:
def backtrace(parent, start, end):
path = [end]
while path[-1] != start:
path.append(parent[path[-1]])
path.reverse()
return path
def bfs(graph, start, end):
parent = {}
queue = []
queue.append(start)
while queue:
node = queue.pop(0)
if node == end:
return backtrace(parent, start, end)
for adjacent in graph.get(node, []):
if node not in queue :
parent[adjacent] = node # <<<<< record its parent
queue.append(adjacent)
print(bfs(graph, 'A', 'F'))
和图(有向图)
graph = {'A': ['C', 'D', 'B'],
'B': ['C', 'E'],
'C': ['E'],
'D': ['F'],
'E': ['F']}
我们可以看到第二种方式可以节省内存成本,因为队列不需要存储路径,并且队列和父映射的空间复杂度都是O(V),其中V是顶点数.而且,最终的回溯过程最多花费额外的 O(V) 时间。
那么,在找到有向图中两个节点之间的最短或所有路径方面,第二种方法是否在所有方面都优于第一种方法?我们可以认为第二种是对 BFS 基础版本的优化(第一种方式)吗?
【问题讨论】:
-
顺便说一句,
queue = []和list.pop(0)极大地减慢了代码速度,使两种算法都成为二次方。如果您需要从序列的前面弹出,尤其是在循环中,请使用collections.deque()。
标签: python algorithm time-complexity breadth-first-search space-complexity