女孩和机器人一起思考

一起动脑筋 · 先看一个小故事

女孩在地上画圈:一步能到的地方先看完,再看两步能到的地方。

把过程摊开来看

沿着编号看一遍,再用自己的话讲一遍
  1. 第 0 层起点
  2. 第 1 层一步可达
  3. 第 2 层两步首次可达
  4. 队列保持先后顺序

广度优先搜索按层扩展。

把起点入队,取出一个点后加入尚未发现的邻居。常在入队时标记,避免同一个点反复排队。

观察队列怎样决定探索顺序

图的边是 A—B、A—C、B—D、C—E。邻居按字母顺序入队,左边是队首。

第 1 步 · 从 A 开始
A

已发现 A,距离是 0。

第 2 步 · 取出 A
BC

把尚未发现的 B、C 入队并标记,它们距离为 1。

第 3 步 · 取出 B
CD

D 入队,距离为 2。C 仍排在 D 前面。

第 4 步 · 取出 C
DE

E 入队,距离为 2。第一层已处理完。

第 5 步 · 取出 D 和 E
空队列

没有未发现的新邻居。本例访问顺序 A、B、C、D、E。

01什么是 BFS?

BFS(Breadth-First Search,广度优先搜索)会从起点开始一层一层向外扩散。

起点第 1 层第 2 层第 3 层

02为什么像水波?

往水里丢一颗石子,波纹先到近处,再到更远处。

BFS 也是先处理离起点更近的状态,再处理更远的状态。

03BFS 为什么使用队列?

队列是先进先出。

先发现的节点先处理,正好能保证较近的一层先被展开。

发现新节点加入队尾从队头依次处理

04基本代码框架

std::queue<int> q;
q.push(start);
visited[start] = true;

while (!q.empty()) {
    int u = q.front();
    q.pop();

    for (int v : graph[u]) {
        if (!visited[v]) {
            visited[v] = true;
            q.push(v);
        }
    }
}

05为什么通常在入队时就标记 visited?

如果等到出队时才标记,同一个节点可能被多个前驱重复加入队列。

06BFS 能做什么?

  • 按层遍历树
  • 无权图最短步数
  • 迷宫最短路
  • 连通性搜索
  • 多源扩散问题

你已经知道了什么

  • BFS 按距离层次逐层扩散。
  • BFS 通常使用队列。
  • 先发现的节点先被处理。
  • 通常在第一次发现节点时就标记 visited。
  • BFS 是无权最短路的重要基础。

下一篇:用 BFS 找最短的路

轮到你来试一试

起点的所有一层邻居还没处理完,就一路深入十层,还是 BFS 吗?

想好了吗?点开看解释

不是通常的广度优先顺序。BFS 要先处理较近的层。