导入
和上次学习DFS一样,我先给出BFS题目的经典模板(如下)
/**
* 广度优先搜索
* @param Vs 起点
* @param Vd 终点
*/
bool BFS(Node& Vs, Node& Vd){
queue<node> Q;
Node Vn, Vw;
int i;
//初始状态将起点放进队列Q
Q.push(Vs);
hash(Vw) = true;//设置节点已经访问过了!
while (!Q.empty()){//队列不为空,继续搜索!
//取出队列的头Vn
Vn = Q.front();
//从队列中移除
Q.pop();
while(Vw = Vn通过某规则能够到达的节点){
if (Vw == Vd){//找到终点了!
//把路径记录,这里没给出解法
return true;//返回
}
if (isValid(Vw) && !visit[Vw]){
//Vw是一个合法的节点并且未走过
Q.push(Vw);//加入队列Q
hash(Vw) = true;//设置节点走过
}
}
}
return false;//无解
} </node>
下面开始我们的学习(以下内容借鉴于leetcode)
首先介绍一下BFS,有文章是这么介绍BFS,我们有“一往无前的DFS”也有“齐头并进的BFS”,没错,BFS用通俗易懂的话来概括就是“齐头并进”
广度优先遍历」的思想在生活中随处可见:
如果我们要找一个医生或者律师,我们会先在自己的一度人脉中遍历(查找),如果没有找到,继续在自己的二度人脉中遍历(查找),直到找到为止。
把一块石头投入平静的水面,激起的一层一层波纹就呈现「广度优先遍历」的特点。
广度优先遍历呈现出「一层一层向外扩张」的特点,先看到的结点先遍历,后看到的结点后遍历,因此「广度优先遍历」可以借助「队列」实现。
说明:遍历到一个结点时,如果这个结点有左(右)孩子结点,依次将它们加入队列。
友情提示:广度优先遍历的写法相对固定,我们不建议大家背代码、记模板。在深刻理解广度优先遍历的应用场景(找无权图的最短路径),借助「队列」实现的基础上,多做练习,写对代码就是自然而然的事情了。
例题
-
岛屿数量
该题也是非常经典了,之前我们也已经使用DFS做过这道题了,今天我们再次将其拿出,用BFS做一遍~~~
为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则将其加入队列(注意哦,是将其对应的下标存放到队列中的)开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0 直到队列为空,搜索结束。
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int nr = grid.size();//行数
if (!nr) return 0;//判断边界情况
int nc = grid[0].size();//列数
int num_islands = 0;//用于计数
//遍历二维网格
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
//满足条件时进来,否则进入下一次循环
if (grid[r][c] == '1') {
++num_islands;
grid[r][c] = '0';
//定义一个队列,用于存放下标信息
//注意对pair的理解,可以看作是内部有两个元素的结构体
queue<pair<int, int>> neighbors;
neighbors.push({r, c});//将'1'的下标信息入队
while (!neighbors.empty()) {
pair<int,int> rc = neighbors.front();//访问队首元素
neighbors.pop();//队首元素出队
int row = rc.first;//队首元素所对应的行号
int col = rc.second;//队首元素所对应的列号
//将它上下左右的‘1’都同化成‘0’
//上
//row - 1 >= 0 判断位置是否合法
if (row - 1 >= 0 && grid[row-1][col] == '1') {
neighbors.push({row-1, col});
grid[row-1][col] = '0';
}
//下
//row + 1 < nr 判断位置是否合法
if (row + 1 < nr && grid[row+1][col] == '1') {
neighbors.push({row+1, col});
grid[row+1][col] = '0';
}
//左
//col - 1 >= 0 判断位置是否合法
if (col - 1 >= 0 && grid[row][col-1] == '1') {
neighbors.push({row, col-1});
grid[row][col-1] = '0';
}
//右
//col + 1 < nc 判断位置是否合法
if (col + 1 < nc && grid[row][col+1] == '1') {
neighbors.push({row, col+1});
grid[row][col+1] = '0';
}
}
}
}
}
return num_islands;
}
};
该代码较长,建议读者一边调试一边理解