作者的话:最近有点时间,开始回来写写算法相关的文章
BFS算法框架
前言
BFS(广度优先级搜索)和DFS(深度优先级搜索)是比较常用的算法,其中DFS算是一种回溯算法,在二叉树中就相当于前序遍历算法。这里先分析BFS算法,为什么呢?因为BFS比较简单!废话少说,直接上分析!
算法分析
BFS相对于DFS最主要的区别在于:BFS找到的路径一定是最短的,但是空间复杂度比DFS要大很多。
BFS算法的核心思想实际上就是将问题抽象成“图”,从一个点开始,向周围扩散。一般来说,我们写BFS算法常用的数据结构是“队列”,每次都将一个节点周围的所有节点加入队列。
BFS算法是出现的场景实际上就是让你在一幅“图”里面找出从“起点”到“终点”的最短距离。把算法本质搞清楚之后,问题都能化归为基本问题。
如果上面的分析有点枯燥?不要紧,直接上栗子:
如走迷宫,有的格子周围的墙壁不能走,让你算从起点到终点的最短距离是多少?如果这个迷宫某些格子有“传送门”呢?
再比如有两个单词,要求通过替换某些字母,把其中一个变成另外一个,每次只能替换一个字母,最少要替换几次?
再比如连连看游戏,消除两个方块的条件不仅仅是图案相同,还要保证两个方块之间的最短连线不能多于两个两个拐点。你玩连连看,点击两个坐标,程序是如何找到最短连线的?如何判断最短连线有几个拐点?
。。。
其实,上面的例子无一不是一幅“图”,让你从起点走到终点,问最短路径,实则BFS本质。
BFS算法框架
上面分析完了,下面直接上算法框架伪代码:
// 计算从起点 start 到终点 target 的最近距离
int BFS(Node start, Node target) {
Queue<Node> q; // 核心数据结构
Set<Node> visited; // 避免走回头路
q.offer(start); // 将起点加入队列
visited.add(start);
int step = 0; // 记录扩散的步数
while (q not empty) {
int sz = q.size();
/* 将当前队列中的所有节点向四周扩散 */
for (int i = 0; i < sz; i++) {
Node cur = q.poll();
/* 划重点:这里判断是否到达终点 */
if (cur is target)
return step;
/* 将 cur 的相邻节点加入队列 */
for (Node x : cur.adj())
if (x not in visited) {
q.offer(x);
visited.add(x);
}
}
/* 划重点:更新步数在这里 */
step++;
}
}
记住:因为BFS都是每次都是所有节点一起遍历,因此BFS总能比较快地找到最短路径。