Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

广度优先搜索

复习

  • 字典树(进阶):字典树按字符逐层组织字符串
  • 图:由节点和边组成
  • 图的表示:邻接矩阵与邻接表

TL;DR

  • 广度优先搜索一层一层向外扩张
  • 它用队列维护待访问的节点
  • 在无权图中,它第一次到达某点就是最短路径
  • 访问过的节点要标记,避免绕圈

正文

  存好图之后,第一个问题是:怎样系统地把它走一遍? 有两种经典走法,先看广度优先搜索(BFS,Breadth-First Search)。

一层一层往外扩

  BFS 的策略像水波扩散:从起点开始,先访问它的所有直接邻居,再访问邻居的邻居,一层一层往外推。

  要按这个顺序走,靠的正是队列:起点入队;每次从队首取出一个节点访问,把它的、还没访问过的邻居都加入队尾。因为队列是先进先出,先入队的(更靠近起点)先被处理,天然形成“一层一层”的顺序。

  同时,要用一个标记记录“哪些节点已经访问过”。否则遇到环,就可能反复绕圈、永远走不完。

为什么它能找到最短路径

  BFS 有一个非常重要的性质:在无权图里,它第一次到达某个节点时,走的就是边数最少的路径。

  道理很直觉:BFS 是一圈一圈扩散的,先访问的一定是离起点近的。当你第一次碰到目标时,前面那些更近的层都已经处理过了,所以不可能有更短的走法还没被发现。第一次到达,就是最短。

  注意,这个结论只对无权图(或者说每条边代价相同)成立。如果边有权重,就得用后面的 Dijkstra 等算法了。

它能做什么

  因为“按层”“最短”这两个性质,BFS 常被用来:

  • 求无权图的最短路径
  • 计算“几度人脉”这样的关系距离
  • 网络爬虫按层抓取

  只要问题问的是“最少几步能到”,BFS 往往就是答案。

  那么,如果不在意“最短”,只想尽快探遍所有能到的角落呢?那就轮到深度优先搜索了。

思考题 1

  BFS 为什么用队列,而不是栈?

思考题 2

  为什么在无权图里,BFS 第一次到达某节点就是最短路径?

小结

知识点

  • BFS 一层层向外扩张,用队列维护待访问节点
  • 需标记已访问节点,避免绕圈
  • 无权图中第一次到达即最短路径
  • 常用于无权最短路、人脉距离、爬虫

参考资料

  1. Wikipedia(zh):广度优先搜索:按层扩展的图遍历算法
  2. Wikipedia(zh):队列:BFS 依赖的先进先出结构

思考题答案(仅供参考)

思考题 1

  因为 BFS 要“先访问离起点近的”,而队列是先进先出,先入队的节点会先被处理,保证按层次推进。若用栈(后进先出),就会变成一条路走到底,那是 DFS 的行为。

思考题 2

  因为 BFS 按层扩散,先访问的一定离起点更近。第一次到达某个节点时,所有更近的层都已经被处理完,不可能还存在一条更短、却还没被发现的路径,所以此时的距离就是最短的。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪