为啥 BFS 用 2 种颜色标记节点,而 DFS 用 3 种颜色标记节点?

Posted

技术标签:

【中文标题】为啥 BFS 用 2 种颜色标记节点,而 DFS 用 3 种颜色标记节点?【英文标题】:Why BFS signs nodes with 2 colors, and DFS with 3 colors?为什么 BFS 用 2 种颜色标记节点,而 DFS 用 3 种颜色标记节点? 【发布时间】:2013-02-03 17:48:13 【问题描述】:

这件事突然出现在我的脑海里。

为什么我们在 BFS 图遍历中只使用 2 种颜色

DFS 需要 3 个吗?

例如:来自***:

BFS:

procedure BFS(G,v):
2      create a queue Q
3      enqueue v onto Q
4      mark v
5      while Q is not empty:
6          t ← Q.dequeue()
7          if t is what we are looking for:
8              return t
9          for all edges e in G.adjacentEdges(t) do
12             u ← G.adjacentVertex(t,e)
13             if u is not marked:
14                  **mark u**
15                  enqueue u onto Q
16     return none

DFS:

  procedure DFS(G,v):
2      label v **as explored**
3      for all edges e in G.adjacentEdges(v) do
4          if edge e is unexplored then
5              w ← G.adjacentVertex(v,e)
6              if vertex w is unexplored then
7                  label e as a **discovery edge**
8                  recursively call DFS(G,w)
9              else
10                 label e as a **back edge**

为什么 2 种颜色不足以用于 DFS? 为什么 BFS 会减少 3 种颜色?

这是另一个 BFS(这次是 3 种颜色):

【问题讨论】:

【参考方案1】:

两种算法都有不同数量的颜色,因为它们用于表示根本不同类型的信息。

在 BFS 和 DFS 中,节点都需要标记为未探索节点或已探索节点。至少需要两种颜色来表示此信息。

在您上面列出的 DFS 实现中,该实现还使用颜色将边缘分类为“发现边缘”(形成算法生成的深度优先搜索树的边缘)或“后边缘”(移动的边缘从 DFS 树的较深部分到 DFS 树的较浅部分)。这些颜色用于为边缘着色,而不是节点。因此,边缘需要三种颜色 - 未探索边缘、“发现”边缘和后边缘。

希望这会有所帮助!

【讨论】:

我添加了 3 种颜色的 BFS 示例。为什么需要这个?为什么我们需要对边缘进行分类? @EladBenda-所有这些都取决于应用程序。您必须对边进行分类没有根本原因,而且通常您也不需要这样做。一些实现可能在 BFS 中使用三种颜色来区分未访问、已访问但尚未扩展和已访问并已扩展。老实说,我认为这不值得担心。这完全取决于您想对搜索做什么,而不是算法的一些基本特征。【参考方案2】:

如果我们用简单的话来解释这一点,在 BFS 中,一旦我们访问了一个节点,它就意味着它的所有邻居也都被访问了,我们不需要再次访问那个顶点。 但是在 DFS 中,有一个称为 Backtracking 的操作,这意味着我们可能需要再次访问一个已经访问过的节点,并且它的所有邻居都不会一次被访问,因此使用第三种颜色灰色表示“是的!它已被访问过”并且您不需要打印它,但是该节点的邻居仍然未被访问”

【讨论】:

【参考方案3】:

在 BFS 的应用中,我们也需要 3 种颜色的节点。一个简单的例子是使用 BFS 打印 每个 无向图的顶点和边一次。我们不能只用两种颜色来做到这一点。要了解为什么会这样,让我们​​考虑一下位于我们当前正在探索的边的另一端的顶点的状态(用于迭代)。另一端的顶点可以 (a) 已经处理 (b) 尚未发现 (c) 已经坐在队列中,等待处理。如果是(a),我们之前已经看到了当前的边,所以我们不需要再打印了。对于(b)和(c),我们是第一次看到它,我们需要打印它。好的,足够好了。所以,我们决定只使用一个标志,visited,对于 (a) 将是 true,对于 (b) 和 (c) 将是 false,这样我们就可以决定何时打印边缘,何时不打印到。但是,因此,我们刚刚确定我们需要为队列中的顶点保留visited 标志false,即情况(c)。因此,我们将无法在推入队列时对其进行标记。只有当我们探索了与它相连的所有边时,我们才能标记它。结果,当在迭代中遇到情况(c)时,我们将无法判断另一端的顶点是否已经在队列中(除非我们明确搜索队列)。我们最终会再次将它推入队列并最终得到一个错误的答案。

【讨论】:

以上是关于为啥 BFS 用 2 种颜色标记节点,而 DFS 用 3 种颜色标记节点?的主要内容,如果未能解决你的问题,请参考以下文章

图的基本算法(BFS和DFS)

图的DFS和BFS

深度优先遍历(DFS)和广度优先遍历(BFS)

hdu254 DFS+BFS

学习笔记:图的DFS和BFS的两种搜索办法

HDU 2102 A计划 DFS与BFS两种写法