【发布时间】:2022-01-25 03:37:49
【问题描述】:
在谷歌上搜索了好几个小时后,我仍然没有找到对这个问题的深入、直观和可靠证明的处理方法。我在一些不知名的论坛上找到的最接近的文章是:https://11011110.github.io/blog/2013/12/17/stack-based-graph-traversal.html。我也看到过这个 Stack Overflow 问题DFS vs BFS .2 differences,但回复并没有达成明确的共识。
那么问题来了: 我已经看到它(在维基百科以及 Tim Roughgarden 阐明的算法中)指出,要将 BFS 实现转换为迭代 DFS 实现,需要进行以下两个更改:
非递归实现类似于广度优先搜索,但在两个方面有所不同: 它使用堆栈而不是队列,并且 它延迟检查是否已发现顶点,直到顶点从堆栈中弹出,而不是在添加顶点之前进行此检查。
任何人都可以通过直觉或示例帮助解释这里第二个区别的原因吗?具体来说:BFS、迭代 DFS 和递归 DFS 之间的区别因素是什么,需要将检查推迟到仅针对迭代 DFS 出栈之后?
这是 BFS 的基本实现:
def bfs(adjacency_list, source):
explored = [False] * len(adjacency_list)
queue = deque()
queue.append(source)
explored[source] = True
while queue:
node = queue.popleft()
print(node)
for n in adjacency_list[node]:
if explored[n] == False:
explored[n] = True
queue.append(n)
如果我们简单地将队列换成堆栈,我们会得到这个 DFS 的实现:
def dfs_stack_only(adjacency_list, source):
explored = [False] * len(adjacency_list)
stack = deque()
stack.append(source)
explored[source] = True
while stack:
node = stack.pop()
print(node)
for n in adjacency_list[node]:
if explored[n] == False:
explored[n] = True
stack.append(n)
这两种算法之间的唯一区别是我们将 BFS 中的队列交换为 DFS 中的堆栈。 DFS 的这种实现实际上产生了不正确的遍历(在一个非简单的图中;可能对于一个非常简单的图它可能无论如何都会产生一个正确的遍历)。
我相信这是上面链接的文章中提到的“错误”。
但是,可以通过以下两种方式之一来解决此问题。
这两种实现中的任何一种都会产生正确的遍历:
首先,上述来源中建议的实现,检查延迟到从堆栈中弹出节点之后。此实现会导致堆栈上出现许多重复项。
def dfs_iterative_correct(adjacency_list, source):
explored = [False] * len(adjacency_list)
stack = deque()
stack.append(source)
while stack:
node = stack.pop()
if explored[node] == False:
explored[node] = True
print(node)
for n in adjacency_list[node]:
stack.append(n)
另外,这是一种流行的在线实现(这个取自 Geeks for Geeks),它也产生了正确的遍历。堆栈上有一些重复项,但几乎没有以前的实现那么多。
def dfs_geeks_for_geeks(adjacency_list, source):
explored = [False] * len(adjacency_list)
stack = deque()
stack.append(source)
while len(stack):
node = stack.pop()
if not explored[node]:
explored[node] = True
print(node)
for n in adjacency_list[node]:
if not explored[n]:
stack.append(n)
因此,总而言之,似乎差异不仅在于您何时检查节点的已访问状态,还在于您何时将其实际标记为已访问。此外,为什么立即将其标记为已访问对 BFS 工作得很好,但对 DFS 却不行?非常感谢任何见解!
谢谢!
【问题讨论】:
标签: graph stack depth-first-search breadth-first-search graph-traversal