BFS 和 DFS 的区别

2025年4月19日 | 阅读 9 分钟

在了解 BFS 和 DFS 的区别之前,我们首先应该分别了解 BFS 和 DFS。

什么是 BFS?

BFS 代表 **广度优先搜索**。它也称为 **层序遍历**。队列数据结构用于广度优先搜索遍历。当我们在图中对 BFS 算法进行遍历时,可以将任何节点视为根节点。

让我们考虑下面的图来进行广度优先搜索遍历。

BFS vs. DFS

假设我们将节点 0 视为根节点。因此,遍历将从节点 0 开始。

BFS vs. DFS

一旦节点 0 从队列中移除,它就会被打印并标记为 **已访问节点**。

一旦节点 0 从队列中移除,节点 0 的相邻节点将插入队列,如下所示:

BFS vs. DFS

现在,节点 1 将从队列中移除;它将被打印并标记为已访问节点。

一旦节点 1 从队列中移除,节点 1 的所有相邻节点都将添加到队列中。节点 1 的相邻节点是 0、3、2、6 和 5。但我们必须只将未访问的节点插入队列。由于节点 3、2、6 和 5 均未访问;因此,这些节点将被添加到队列中,如下所示:

BFS vs. DFS

队列中的下一个节点是 3。因此,节点 3 将从队列中移除,打印并标记为已访问,如下所示:

BFS vs. DFS

一旦节点 3 从队列中移除,节点 3 的所有相邻节点(已访问节点除外)都将添加到队列中。节点 3 的相邻节点是 0、1、2 和 4。由于节点 0、1 已被访问,而节点 2 存在于队列中;因此,我们只需要将节点 4 插入队列。

BFS vs. DFS

现在,队列中的下一个节点是 2。因此,2 将从队列中删除。它将被打印并标记为已访问,如下所示:

BFS vs. DFS

一旦节点 2 从队列中移除,节点 2 的所有相邻节点(已访问节点除外)都将添加到队列中。节点 2 的相邻节点是 1、3、5、6 和 4。由于节点 1 和 3 已被访问,而 4、5、6 已被添加到队列中;因此,我们不需要将任何节点插入队列。

下一个元素是 5。因此,5 将从队列中删除。它将被打印并标记为已访问,如下所示:

BFS vs. DFS

一旦节点 5 从队列中移除,节点 5 的所有相邻节点(已访问节点除外)都将添加到队列中。节点 5 的相邻节点是 1 和 2。由于两个节点都已被访问;因此,没有顶点需要插入队列。

下一个节点是 6。因此,6 将从队列中删除。它将被打印并标记为已访问,如下所示:

BFS vs. DFS

一旦节点 6 从队列中移除,节点 6 的所有相邻节点(已访问节点除外)都将添加到队列中。节点 6 的相邻节点是 1 和 4。由于节点 1 已被访问,而节点 4 已被添加到队列中;因此,没有顶点需要插入队列。

队列中的下一个元素是 4。因此,4 将从队列中删除。它将被打印并标记为已访问。

一旦节点 4 从队列中移除,节点 4 的所有相邻节点(已访问节点除外)都将添加到队列中。节点 4 的相邻节点是 3、2 和 6。由于所有相邻节点都已被访问;因此,没有顶点需要插入队列。

什么是 DFS?

DFS 代表 **深度优先搜索**。在 DFS 遍历中,使用栈数据结构,它遵循 LIFO(后进先出)原则。在 DFS 中,遍历可以从任何节点开始,或者我们可以说,只要问题中没有提及根节点,任何节点都可以被视为根节点。

在 BFS 的情况下,从队列中删除的元素,被删除节点的相邻节点会被添加到队列中。相反,在 DFS 中,从栈中移除的元素,只会被删除节点的其中一个相邻节点添加到栈中。

让我们考虑下面的图来进行深度优先搜索遍历。

BFS vs. DFS

将节点 0 视为根节点。

首先,我们将元素 0 插入栈,如下所示:

BFS vs. DFS

节点 0 有两个相邻节点,即 1 和 3。现在我们可以只选择一个相邻节点,1 或 3,进行遍历。假设我们选择节点 1;因此,1 被插入栈并被打印,如下所示:

BFS vs. DFS

现在我们将查看节点 1 的相邻顶点。节点 1 的未访问相邻顶点是 3、2、5 和 6。我们可以选择这四个顶点中的任何一个。假设我们选择节点 3 并将其插入栈,如下所示:

BFS vs. DFS

考虑节点 3 的未访问相邻顶点。节点 3 的未访问相邻顶点是 2 和 4。我们可以选择任一顶点,即 2 或 4。假设我们选择顶点 2 并将其插入栈,如下所示:

BFS vs. DFS

节点 2 的未访问相邻顶点是 5 和 4。我们可以选择任一顶点,即 5 或 4。假设我们选择顶点 4 并将其插入栈,如下所示:

BFS vs. DFS

现在我们将考虑节点 4 的未访问相邻顶点。节点 4 的未访问相邻顶点是节点 6。因此,元素 6 被插入栈,如下所示:

BFS vs. DFS

将元素 6 插入栈后,我们将查看节点 6 的未访问相邻顶点。由于节点 6 没有未访问的相邻顶点,因此我们无法超出节点 6。在这种情况下,我们将执行 **回溯**。栈顶元素,即 6,将被弹出栈,如下所示:

BFS vs. DFS
BFS vs. DFS

栈顶元素是 4。由于节点 4 没有剩余未访问的相邻顶点;因此,节点 4 被弹出栈,如下所示:

BFS vs. DFS
BFS vs. DFS

栈中的下一个顶部元素是 2。现在,我们将查看节点 2 的未访问相邻顶点。由于只剩下一个未访问的节点,即 5,因此节点 5 将被推到 2 之上的栈中并被打印,如下所示:

BFS vs. DFS

现在我们将查看节点 5 的仍然未访问的相邻顶点。由于没有剩余的顶点需要访问,因此我们将元素 5 从栈中弹出,如下所示:

BFS vs. DFS

我们无法进一步访问 5,因此我们需要执行回溯。在回溯中,栈顶元素将被弹出。栈顶元素是 5,它将被弹出栈,我们将返回到节点 2,如下所示:

BFS vs. DFS

现在我们将查看节点 2 的未访问相邻顶点。由于没有剩余的相邻顶点需要访问,因此我们执行回溯。在回溯中,栈顶元素,即 2,将被弹出栈,我们将返回到节点 3,如下所示:

BFS vs. DFS
BFS vs. DFS

现在我们将查看节点 3 的未访问相邻顶点。由于没有剩余的相邻顶点需要访问,因此我们执行回溯。在回溯中,栈顶元素,即 3,将被弹出栈,我们将返回到节点 1,如下所示:

BFS vs. DFS
BFS vs. DFS

弹出元素 3 后,我们将查看节点 1 的未访问相邻顶点。由于没有剩余的顶点需要访问;因此,将执行回溯。在回溯中,栈顶元素,即 1,将被弹出栈,我们将返回到节点 0,如下所示:

BFS vs. DFS
BFS vs. DFS

我们将查看节点 0 的仍然未访问的相邻顶点。由于没有剩余的相邻顶点需要访问,因此我们执行回溯。在此过程中,栈中只剩一个元素,即 0,将被弹出栈,如下所示:

BFS vs. DFS

正如我们从上图可以观察到的,栈是空的。因此,我们必须在这里停止 DFS 遍历,而被打印的元素就是 DFS 遍历的结果。

BFS 和 DFS 之间的区别

以下是 BFS 和 DFS 之间的区别:

 BFSDFS
全称BFS 代表广度优先搜索。DFS 代表深度优先搜索。
技术它是一种基于顶点的技术,用于在图中查找最短路径。它是一种基于边的技术,因为从起点到终点节点,首先会探索边上的顶点。
定义BFS 是一种遍历技术,其中首先探索同一级别的所有节点,然后我们移动到下一级别。DFS 也是一种遍历技术,其中遍历从根节点开始,并尽可能深入地探索节点,直到我们到达没有未访问相邻节点的节点。
数据结构BFS 遍历使用队列数据结构。DFS 遍历使用栈数据结构。
回溯BFS 不使用回溯概念。DFS 使用回溯来遍历所有未访问的节点。
边数BFS 查找从源顶点到目标顶点的最短路径,具有最少的边数。在 DFS 中,需要更多的边来从源顶点遍历到目标顶点。
最优性BFS 遍历对于那些距离源顶点较近的要搜索的顶点是最优的。DFS 遍历对于那些解决方案距离源顶点较远的图是最优的。
速度BFS 比 DFS 慢。DFS 比 BFS 快。
对决策树的适用性它不适用于决策树,因为它需要首先探索所有相邻节点。它适用于决策树。基于决策,它会探索所有路径。找到目标时,它会停止遍历。
内存效率它不是内存高效的,因为它比 DFS 需要更多的内存。它是内存高效的,因为它比 BFS 需要更少的内存。
不连通分量BFS 可能需要多次运行才能完全探索不连通的分量。此方法系统地检查图中的每个节点,在进入下一级别之前访问每个节点的每个邻居。深度优先搜索 (DFS) 是一种有效的算法,用于探索从给定起点可以到达的所有顶点。这使其成为遍历图中不连通分量的有用工具。DFS 系统地访问每个可达顶点,直到到达死胡同为止,仔细跟踪每个路径。
拓扑排序BFS(广度优先搜索)不直接支持拓扑排序。此方法更适合于其他类型的图遍历。DFS 可用于以特定顺序(称为拓扑排序)排列有向无环图 (DAG) 的节点。这对于诸如基于依赖项安排作业之类的任务至关重要。
路径查找虽然 BFS 能保证根据边的数量找到两点之间的最短路径,但 DFS 不一定能找到最短路径。当仅仅找到两点之间的路径就足够时,DFS 会很有用。该算法允许您探索所有连接的顶点,这在特定路径不像到达目的地那么重要的某些情况下很有用。
密集图中的空间复杂度在具有大量边的密集图(高度连接的图)中,广度优先搜索 (BFS) 算法由于需要将所有相邻顶点存储在队列中,因此可能需要更多内存。这是因为 BFS 在进入下一级别之前会探索当前级别的所有邻居节点,这可能导致队列大小过大。DFS 由于其递归结构,在这种情况下通常需要更少的内存。深度优先搜索算法在回溯之前会完全探索一条路径,这可能比广度优先搜索更有效。

下一个主题栈和堆的区别