概述
宽度优先搜索算法,Breadth First Search,又称广度优先搜索,是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra 单源最短路劲算法和 Prim 最小生成树算法都采用了和宽度优先搜索类似的思想。
BFS属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。从算法的观点,所有因为展开节点而得到的子节点都会被加进一个先进先出的队列(FIFO)中。一般的实验里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如队列 queue 或是链表 linked-list),而被检验过的节点则被放置在被称为 closed 的容器中。
闪电可以看成自然界中的 BFS,如下图所示。
BFS 详细解释
已知图 G=(V, E) 和一个源顶点 s,宽度优先搜索以一种系统的方式探寻 G 的边,从而发现 s 所能到达的所有顶点,并计算 s 到所有这些顶点的距离(最少边数),该算法同时能生成一棵根为 s 且包括所有可达顶点的宽度优先树。对从 s 可达的任意顶点 v,宽度优先树中从 s 到 v 的路径对应于图 G 中从 s 到 v 的最短路径,即包含最小边数的路径。该算法对有向图和无向图同样适用。
之所以称之为宽度优先算法,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和 s 距离为 k 的所有顶点,然后再去搜索和 s 距离为 k+l 的其他顶点。
思路
广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
图例
树的遍历
假设我们有如下图所示的一颗树。
从树根节点 1 开始,到节点 12 的 BFS 搜索过程如下:
当前访问节点 | 已经访问节点 | 下一次访问节点 |
1 | {1} | {2 3 4} |
2 | {1 2} | {3 4 5 6} |
3 | {1 2 3} | {4 5 6 7 8} |
4 | {1 2 3 4} | {5 6 7 8} |
5 | {1 2 3 4 5} | {6 7 8} |
6 | {1 2 3 4 5 6} | {7 8} |
7 | {1 2 3 4 5 6 7} | {8} |
8 | {1 2 3 4 5 6 7 8} | {9 10} |
9 | {1 2 3 4 5 6 7 8 9} | {10 11} |
10 | {1 2 3 4 5 6 7 8 9 10} | {11 12} |
11 | {1 2 3 4 5 6 7 8 9 10 11} | {12} |
12 | {1 2 3 4 5 6 7 8 9 10 11 12} |
从上表可以看出,我们要维护两个队列 queue,一个用于保存已经访问的节点,另外一个用于保存下一次访问的节点。
图的遍历
假设我们有如下图所示的一个图。
从 V0 开始,到 V6 的 BFS 搜索过程如下:
当前访问节点 | 已经访问节点 | 下一次访问节点 |
V0 | {V0} | {V3 V1 V2} |
V3 | {V0 V3} | {V1 V2 V5} |
V1 | {V0 V3 V1} | {V2 V5 V4} |
V2 | {V0 V3 V1 V2} | {V5 V4 V6} |
V5 | {V0 V3 V1 V2 V5} | {V4 V6} |
V4 | {V0 V3 V1 V2 V5 V4} | {V6} |
V6 | {V0 V3 V1 V2 V5 V4 V6} |