相关笔记

概览

本节介绍 广度优先搜索(Breadth-First Search, BFS)算法,它是图算法中最基础、最重要的搜索策略之一。BFS 从源顶点 出发,逐层向外扩展,先访问距 为 1 的所有顶点,再访问距 为 2 的所有顶点,依此类推。BFS 使用队列(FIFO)作为辅助数据结构,通过颜色标记(WHITE/GRAY/BLACK)、距离 前驱 三个属性系统地探索图。BFS 的核心性质是:它能找到从源顶点到所有可达顶点的最短路径(在无权图中以边数计)。BFS 的运行时间为

核心要点:

  • BFS 使用队列实现逐层扩展,时间复杂度
  • BFS 计算出的距离 等于最短路径距离
  • 前驱子图 是一棵广度优先树(BFS tree)
  • BFS 是许多高级图算法的基础:Dijkstra、二部图判定、无权图最短路径等

知识结构总览

flowchart TD
    A["20.2 广度优先搜索 (BFS)"] --> B["算法流程"]
    A --> C["核心性质与定理"]
    A --> D["BFS 树"]
    A --> E["复杂度分析"]
    A --> F["应用与拓展"]

    B --> B1["初始化: 所有顶点 WHITE"]
    B --> B2["源点 s 入队, 标记 GRAY"]
    B --> B3["循环: 出队 u"]
    B --> B4["遍历 Adj[u]"]
    B --> B5["WHITE 邻居: 标记 GRAY, 入队"]
    B --> B6["u 标记 BLACK"]

    C --> C1["引理22.3: BFS队列性质"]
    C --> C2["定理22.4: BFS最短路径"]
    C --> C3["推论22.5: BFS前驱子图是树"]

    D --> D1["前驱子图 G_π"]
    D --> D2["π 属性定义树边"]
    D --> D3["BFS 树包含所有可达顶点"]

    E --> E1["邻接表: O(V+E)"]
    E --> E2["邻接矩阵: O(V²)"]

    F --> F1["Dijkstra 算法基础"]
    F --> F2["二部图判定"]
    F --> F3["社交网络分析"]
    F --> F4["网络爬虫"]

    style A fill:#4a90d9,color:#fff
    style C2 fill:#e74c3c,color:#fff
    style C3 fill:#27ae60,color:#fff

核心思想

核心思想

BFS 的核心策略是逐层扩展:从源点出发,先探索所有距离为 1 的顶点,再探索所有距离为 2 的顶点,依此类推。这种”先到先服务”的探索顺序通过队列(FIFO)自然实现——先被发现的顶点先被处理,其邻居先被探索。BFS 保证每个顶点在被发现时,记录的距离就是从源点到该顶点的最短路径距离

BFS 算法

算法执行流程

  1. 初始化所有顶点为白色(未访问),源点 s 设为灰色(已发现),距离 d[s]=0,前驱为 NIL
  2. 将源点 s 入队 Q
  3. while 队列 Q 非空
  4. 出队顶点 u,将 u 标记为黑色(已处理完毕)
  5. 遍历 u 的每个邻接顶点 v:若 v 为白色,标记为灰色,记录 d[v]=d[u]+1 和前驱,将 v 入队
  6. 队列为空时结束,所有可达顶点的最短路径距离和前驱均已确定
flowchart TD
    A["开始:输入图 G, 源点 s"] --> B["初始化所有顶点为白色<br/>s.color = GRAY, s.d = 0"]
    B --> C["ENQUEUE(Q, s)"]
    C --> D{"队列 Q 非空?"}
    D -- 是 --> E["u = DEQUEUE(Q)<br/>u.color = BLACK"]
    E --> F["遍历 u 的每个邻接顶点 v"]
    F --> G{"v.color == WHITE?"}
    G -- 是 --> H["v.color = GRAY<br/>v.d = u.d + 1<br/>v.pi = u<br/>ENQUEUE(Q, v)"]
    H --> I{"还有未检查的邻居?"}
    G -- 否 --> I
    I -- 是 --> F
    I -- 否 --> D
    D -- 否 --> J["结束:所有可达顶点已访问"]
BFS(G, s)
1  for each vertex u ∈ G.V - {s}
2      u.color = WHITE
3      u.d = ∞
4      u.π = NIL
5  s.color = GRAY
6  s.d = 0
7  s.π = NIL
8  Q = 空队列
9  ENQUEUE(Q, s)
10 while Q ≠ ∅
11     u = DEQUEUE(Q)
12     for each v ∈ G.Adj[u]
13         if v.color == WHITE
14             v.color = GRAY
15             v.d = u.d + 1
16             v.π = u
17             ENQUEUE(Q, v)
18     u.color = BLACK

顶点属性

BFS 顶点属性

BFS 为每个顶点 维护三个属性:

  • :顶点的颜色,取值为:
    • WHITE:尚未被发现(初始状态)
    • GRAY:已被发现但尚未完成对其所有邻居的探索(在队列中)
    • BLACK:已完成对所有邻居的探索(已出队且处理完毕)
  • :从源点 到顶点 距离,即从 的最短路径上的边数。初始值为
  • :顶点 在 BFS 树中的前驱(parent),即 BFS 树中 的父节点。初始值为 NIL

BFS 的执行过程

BFS 的执行过程可以分为三个阶段:

  1. 初始化(第 1-9 行): 将所有顶点(除源点 )标记为 WHITE,距离设为 ,前驱设为 NIL。源点 标记为 GRAY,距离设为 0,前驱设为 NIL,然后入队。

  2. 主循环(第 10-18 行): 当队列非空时,取出队首顶点 ,遍历 的所有邻居 。如果 尚未被发现(WHITE),则将 标记为 GRAY,设置 ,设置 ,并将 入队。处理完 的所有邻居后,将 标记为 BLACK。

  3. 终止: 当队列为空时,BFS 结束。所有从 可达的顶点都已被发现并处理。

BFS 队列性质

引理 22.3(BFS 队列性质)

在 BFS 过程中,队列中的顶点按距离 非递减排列。更精确地说,如果队列中的顶点依次为 ,则 ,且

BFS 最短路径定理

定理 22.4(BFS 最短路径)

是一个有向图或无向图, 为源点。BFS 执行后,对于每个从 可达的顶点 其中 表示从 最短路径距离(以边数计)。对于从 不可达的顶点 ,有

BFS 前驱子图与 BFS 树

前驱子图(Predecessor Subgraph)

BFS 执行后,由前驱属性 定义的有向图 称为前驱子图,其中:

  • (所有有前驱的顶点加上源点)
  • (每个非源点顶点到其前驱的边)

推论 22.5(BFS 前驱子图是 BFS 树)

在 BFS(G, s) 执行后,前驱子图 是一棵==根为 的树==,包含所有从 可达的顶点。对于每个从 可达的顶点 中从 的唯一简单路径就是 中从 的一条最短路径

复杂度分析

BFS 时间复杂度

邻接表表示:

  • 初始化(第 1-7 行):遍历所有顶点,
  • 主循环:每个顶点最多入队一次、出队一次,
  • 遍历所有邻接表:每条边被检查一次(有向图)或两次(无向图),
  • 总计:

邻接矩阵表示:

  • 遍历每个顶点的邻居需要扫描矩阵的一整行,
  • 个顶点,总计

补充理解与拓展

BFS 的发明历史

BFS 的发明可以追溯到 1950 年代末至 1960 年代初的两个独立发现:

  • Edward F. Moore(1959):在论文 “Shortest path through a maze” 中首次系统描述了 BFS 算法,用于求解迷宫中的最短路径问题。该论文发表于 1959 年的 International Symposium on the Theory of Switching。
  • C. Y. Lee(1961):在论文 “An Algorithm for Path Connections and Its Applications” 中独立提出了相同的算法,用于解决电路板布线(PCB routing)问题。该算法后来被称为 “Lee’s algorithm”,至今仍用于 VLSI 设计中的布线。

BFS 是计算机科学中最早被形式化描述的图算法之一,其简洁性和正确性使其成为算法教科书的标配内容。

来源:Moore, E.F., “Shortest path through a maze”, 1959; Lee, C.Y., “An Algorithm for Path Connections and Its Applications”, IRE Trans. Electronic Computers, 1961

BFS 的实际应用

BFS 在现实世界中有广泛的应用:

  1. 社交网络分析:Facebook 的”你可能认识的人”推荐功能基于 BFS——从你的好友出发,逐层扩展寻找共同好友。著名的”六度分隔理论”(任何两个人之间最多通过 6 个中间人相连)可以通过 BFS 验证。Facebook 2016 年的研究表明,全球 Facebook 用户之间的平均距离已缩小到 3.57。

  2. 网络爬虫:搜索引擎的爬虫使用 BFS 从种子 URL 出发,逐层抓取网页。BFS 优先抓取距离种子近的页面,有利于优先收录重要页面。

  3. 洪水填充(Flood Fill):图像处理中的”油漆桶”工具使用 BFS(或 DFS)将连通的同色区域填充为新颜色。BFS 版本的填充模式更均匀。

  4. 无权图最短路径:在边没有权重的图中(如地铁线路图,假设每站间距相同),BFS 直接给出最短路径。

  5. 垃圾回收:编程语言的垃圾回收器使用 BFS/DFS 标记所有从根对象可达的对象,不可达的对象被回收。

来源:Backstrom, L. et al., “Four Degrees of Separation”, Facebook Research, 2012

BFS 与 Dijkstra 算法的关系

BFS 是 Dijkstra 算法在所有边权重相等(例如所有边权重为 1)时的特例:

  • BFS:使用普通队列(FIFO),适用于无权图,时间
  • Dijkstra:使用优先队列(最小堆),适用于非负权图,时间

当所有边权重为 1 时,Dijkstra 算法的优先队列退化为 FIFO 队列(因为新发现的顶点的距离值总是比队列中已有的最小值大 1),此时 Dijkstra 等价于 BFS。

记忆方法: BFS 是 Dijkstra 的”简化版”——当所有”路费”相同时,不需要优先队列,普通队列就够了。

二部图判定(习题 22.2-7 的工程意义)

习题 22.2-7 要求用 BFS 判断无向图是否是二部图(bipartite graph)。二部图判定在工程中有重要应用:

  • 任务调度:将任务分为两组,同组任务不冲突,可以并行执行
  • 图着色:二部图是 2-可着色的,判断二部图是图着色问题的特例
  • 匹配问题:二部图上的最大匹配是经典问题,应用于求职者-岗位匹配、课程-时间槽分配等
  • 社交网络:判断社区结构是否天然分为两组

BFS 判定方法: 从任意顶点出发执行 BFS,交替标记顶点为”红色”和”蓝色”。如果发现某条边的两个端点颜色相同,则图不是二部图;否则是二部图。时间复杂度


易混淆点与辨析

BFS 的距离是边数,不是路径上的权值之和

常见错误:认为 BFS 可以直接用于带权图的最短路径。

正确理解:BFS 计算的距离 是从源点到 最短路径上的边数,即 。对于带权图(边有权重),BFS 不能正确计算最短路径。带权图的最短路径应使用 Dijkstra 算法(非负权)或 Bellman-Ford 算法(允许负权)。

反例: 考虑路径 和路径 。BFS 会选择 2 条边的路径 (距离 20),但实际最短路径是 3 条边的路径 (距离 3)。

BFS 的前驱子图不包含不可达顶点

常见错误:认为 BFS 的前驱子图 包含所有顶点。

正确理解 只包含从源点 可达的顶点。对于从 不可达的顶点 不在 中。

BFS 树不唯一

常见错误:认为 BFS 只产生一棵唯一的 BFS 树。

正确理解:BFS 树取决于邻接表中邻居的排列顺序。不同的邻居顺序可能导致不同的 BFS 树。但无论哪种 BFS 树,从源点到每个顶点的距离 始终等于

BFS 的 GRAY 状态的意义

常见错误:认为 GRAY 状态只是为了标记”已发现”。

正确理解:GRAY 状态表示顶点已发现但尚未完成处理(在队列中等待)。GRAY 状态是 BFS 队列性质的保证——只有 GRAY 顶点在队列中,BLACK 顶点已出队且处理完毕,WHITE 顶点尚未被发现。这种三色标记方案在 DFS 中同样重要。


习题精选

题号题目描述难度
22.2-1在图 22.2(a) 上从顶点 执行 BFS,展示 的值★☆☆
22.2-2BFS 在有向图和无向图上的区别是什么?★☆☆
22.2-3证明 BFS 执行后,对于每条边 ,有 ★★☆
22.2-4给定 BFS 树,说明如何找到从 的最短路径★☆☆
22.2-5证明 BFS 树中从 的路径是 中的最短路径★★☆
22.2-6证明 BFS 中,当顶点 入队时, 的值不会被后续操作改变★★☆
22.2-7用 BFS 判断无向图是否是二部图★★★
22.2-8*(思考题)BFS 的变体★★★
22.2-9*(思考题)BFS 与最短路径树★★★

视频学习指南

资源主题链接说明
MIT 6.006 Lecture 13Breadth-First Searchhttps://www.youtube.com/watch?v=s-CYnVz-uh4Erik Demaine 教授,完整讲解 BFS 算法与正确性证明
MIT 6.006 Lecture 13 (cont.)BFS Shortest Pathshttps://www.youtube.com/watch?v=g5vF8jsnCDgBFS 最短路径性质的严格证明
Abdul BariBFS Algorithmhttps://www.youtube.com/watch?v=pcKY4hjDr6k逐步动画演示 BFS 执行过程
WilliamFisetBFS Graph Algorithmhttps://www.youtube.com/watch?v=oDqjPvD54Ss数据结构系列,含代码实现
NeetCodeBFS Introductionhttps://www.youtube.com/watch?v=-tgVpUgsQ5kLeetCode 刷题视角,含经典 BFS 题目分类
3Blue1BrownGraph Algorithmshttps://www.youtube.com/watch?v=09_LlHjoEiY可视化 BFS/DFS,直观理解搜索过程

教材原文

原文摘录(CLRS 第4版 22.2节)

Breadth-first search is one of the simplest algorithms for searching a graph and the archetype for many important graph algorithms. Given a graph and a distinguished source vertex , breadth-first search systematically explores the edges of to discover every vertex that is reachable from .

广度优先搜索是搜索图的最简单算法之一,也是许多重要图算法的原型。给定图 和一个特定的源顶点 ,广度优先搜索系统地探索 的边以发现从 可达的每个顶点。

原文摘录(CLRS 第4版 22.2节)

The breadth-first-search procedure BFS assumes that the input graph is represented using adjacency lists. It attaches several additional attributes to each vertex in the graph. We store the color of each vertex in the attribute , and the predecessor of in the BFS tree in the attribute . When the procedure discovers a vertex , it sets to the distance from the source to .

广度优先搜索过程 BFS 假设输入图 使用邻接表表示。它为图中的每个顶点附加了几个属性。我们将每个顶点 的颜色存储在属性 中,将 在 BFS 树中的前驱存储在属性 中。当过程发现顶点 时,它将 设为从源点 的距离。

原文摘录(CLRS 第4版 22.2节,定理 22.4)

Theorem 22.4 (Correctness of breadth-first search) Let be a directed or undirected graph, and suppose that BFS is run on from a given source vertex . Then, upon termination, for every vertex that is reachable from , .

定理 22.4(广度优先搜索的正确性) 是一个有向图或无向图,假设从给定的源顶点 出发在 上运行 BFS。那么,在终止时,对于每个从 可达的顶点


参见Wiki

  • (概念页尚未创建)

第20章-基本图算法 广度优先搜索