简介
广度优先搜索,是以广度作为第一关键词,当碰到岔口时,首先访问这个岔口能直接到达的所有结点,然后这些结点被访问的顺序,依次继续访问其可以到达的所有结点,直到所有结点都被访问,或者满足终止条件;
算法较为理想的实现方式是使用队列,将前面的元素不断弹出,在搜索过程中,将下一层的元素不断地补在后面,直到队列为空,或是满足条件,完成搜索;
完成demo后,发现本方法适用于求取图像中的连通域个数、大小、排序等,因此作为扩展,在此记录求解连通域的用法;
模板
void BFS(int s){
queue<int> q;
q.push(s);
while(!q.empty()){
取出队首元素top;
访问队首元素top;
将队首元素出队;
将top的下一层结点中,未曾入队的全部入队;
}
}
对于上述模板的说明如下:
- 定义队列 q,并将起点 s 入队;
- 定义 while 循环,循环条件是 q 非空;
- 在 while 循环中,先取出队首的元素 top,然后访问 top,访问结束后令 top 出队;
- 将 top下一层结点中未曾入队的结点全部入队,如果需要记录层号,此时层号加一,同时设置上述结点已经入过队;
- 返回步骤 2,直到队列为空或满足其他终止条件;
Demo
给出一个 m×n 的矩阵,矩阵中的元素为0或1(与二值图像等效),定义位置 (x,y) 与其上下左右四个位置 (x-1, y), (x+1, y), (x, y-1), (x, y+1) 是相邻的。由相邻的点连成的区域就叫连通域,求给定矩阵中连通域的个数,给出 6×7 的矩阵示例如下,首行输入尺寸,随后输入矩阵的值:
6 7
0 1 1 1 0 0 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 1 0
1 1 1 0 1 0 0
1 1 1 1 0 0 0
输出为连通域的个数:
4
问题分析
- 枚举每一个位置的元素,如果为 0,跳过;如果为 1,则使用 BFS 查询邻近的 4 个元素(保证不出界,且不重复访问), 判断其是否为 1,循环往复,知道一个连通域内的 1 全部访问;
- 为了防止走“回头路”,防止重复访问同一个 1,设置一个 bool 型的数组 inq(意为in queue) 来记录每个 1 是否在 BFS 中已经入过队;
- 设置两个数组来表示 4 个方向,用 for 循环省略了 4 个 if;
int row[4] = {
0, 0, 1, -1};
int col[4] = {
1, -1, 0, 0};
for(