图的宽度优先搜索
好的,我们将深入探讨“图的宽度优先搜索”(Breadth-First Search, BFS)这一重要概念。这是一种用于遍历或搜索图数据结构的算法,其核心思想是“由近及远”,逐层探索图中的顶点。
第一步:理解BFS的核心思想与直观比喻
想象一下,你站在一个迷宫的中心点(起点),你的目标是探索整个迷宫。你决定采取一种策略:首先探索所有与你当前位置直接相邻的房间(一步可达),然后再探索与这些相邻房间直接相连的下一批房间(两步可达),如此反复,直到探索完所有房间。你就像在水池中投入一颗石子,涟漪从中心一圈一圈地向外扩散。BFS算法正是模拟了这一过程。
它的核心特征是按距离起点的层次进行遍历。在无权图中,这个“距离”就是指从起点到该顶点所需要经过的最少边数,也称为“跳数”。
第二步:BFS算法的基本流程与关键数据结构
为了实现“一层一层”访问的效果,BFS算法依赖于一个队列 数据结构。队列遵循“先进先出”的原则,这正好符合我们“先访问的顶点,其未被访问的邻居也先被访问”的需求。
算法的基本步骤如下:
-
初始化:选择一个起点顶点
s。我们将顶点分为三种状态:- 未发现:尚未被算法访问到的顶点。
- 已发现:已经被算法发现(加入了队列),但可能还未处理其所有邻居。
- 已访问:已从队列中取出,并处理完其所有邻居的顶点。
我们创建一个队列Q,并将起点s标记为“已发现”并入队。
-
循环遍历:只要队列
Q不为空,就重复以下步骤:
a. 出队:从队列Q的头部取出一个顶点u(这个顶点变为“已访问”)。
b. 探索邻居:检查顶点u的所有未发现的邻居顶点v。对于每一个这样的邻居v:
* 将v标记为“已发现”。
* 将v的“前驱”(或“父节点”)记录为u。这用于后续重建路径。
* 将v放入队列Q的尾部。 -
终止:当队列为空时,算法结束。此时,所有从起点
s可达的顶点都已经被访问过。
第三步:一个具体的例子
考虑一个简单的无向图,顶点集为 {A, B, C, D, E},边集为 {(A,B), (A,C), (B,D), (C,E)}。我们以 A 为起点进行 BFS。
- 初始化:队列 Q = [A]。A 被发现。
- 第一轮循环:
- 出队 A。访问 A。
- 检查 A 的邻居:B 和 C 都是未发现的。
- 标记 B 和 C 为已发现,记录其父节点为 A,并入队。现在 Q = [B, C]。
- 第二轮循环:
- 出队 B。访问 B。
- 检查 B 的邻居:A(已访问),D(未发现)。
- 标记 D 为已发现,记录其父节点为 B,并入队。现在 Q = [C, D]。
- 第三轮循环:
- 出队 C。访问 C。
- 检查 C 的邻居:A(已访问),E(未发现)。
- 标记 E 为已发现,记录其父节点为 C,并入队。现在 Q = [D, E]。
- 第四轮循环:
- 出队 D。访问 D。
- 检查 D 的邻居:B(已访问),没有其他邻居。现在 Q = [E]。
- 第五轮循环:
- 出队 E。访问 E。
- 检查 E 的邻居:C(已访问)。现在 Q = []。
- 算法结束。
访问顺序(即出队顺序)为:A, B, C, D, E。你可以看到,算法确实是先访问了所有与 A 距离为 1 的顶点(B, C),然后再访问距离为 2 的顶点(D, E)。
第四步:BFS的性质与证明
BFS算法具有一些非常重要的性质:
- 最短路径:在无权图中,BFS 自然地计算出了从起点
s到所有可达顶点的最短路径(以边数计)。这是因为 BFS 是按照距离s的层次顺序访问顶点的。当我们通过v的父节点u来发现v时,从s到v的最短路径就是从s到u的最短路径再加上边(u, v)。 - 连通分量:对于无向图,从起点
s开始执行一次 BFS 所访问到的所有顶点,恰好构成了包含s的连通分量。你可以通过 BFS 来计数一个无向图中有多少个连通分量(对每个未发现的顶点执行一次 BFS)。 - 二部图判定:BFS 可以用来判断一个图是否是二部图。在遍历过程中,我们给起点标记为颜色1,然后其邻居标记为颜色2,邻居的邻居标记为颜色1,以此类推。如果在给某个顶点着色时,发现其邻居已经着色且颜色与自己相同,则该图不是二部图。
第五步:BFS的时间与空间复杂度分析
- 时间复杂度:假设图有
V个顶点和E条边。在算法过程中,每个顶点最多入队和出队一次,处理一个顶点的所有邻居的时间与其度数成正比。因此,遍历所有邻居的总时间就是所有顶点的度数之和,即2E(对于无向图)。所以,BFS 的总体时间复杂度为 O(V + E)。这是一个非常高效的算法。 - 空间复杂度:主要空间消耗在于队列、记录顶点状态的数组以及记录父节点的数组。这些都需要 O(V) 的空间。
第六步:BFS的常见应用场景
BFS不仅仅是一个遍历算法,它是许多图论问题的基础工具:
- 社交网络中的“度”分离:寻找两个人之间最短的熟人关系路径。
- 网络爬虫:搜索引擎的网络爬虫使用 BFS 的思想(或类似变种)来系统地抓取网页,先抓取一个页面中的所有链接,再抓取这些链接页面中的所有链接。
- 广播网络:在计算机网络中,BFS 可用于实现广播协议,确保信息以最少的跳数传播到所有节点。
- 迷宫求解:寻找从入口到出口的最短路径。
- 垃圾收集:在编程语言的垃圾回收算法(如复制收集)中,BFS 被用来追踪所有从根节点可达的活动对象。
通过以上六个步骤,我们从思想、流程、实例、性质、复杂度到应用,系统地学习了图的宽度优先搜索。它与深度优先搜索(DFS)相辅相成,是图论算法中最基础且最重要的两大支柱之一。