一、引入两个问题

  1. 给出图1从任意一点开始的广度优先搜索遍历的序列,
    (1)设置BFS返回值为向量的代码;
    (2)设置BFS无返回值,同时点集用字符串表示,要求输出结果打印到屏幕上

    图1

  2. 岛屿数量问题(类似于迷宫问题),来自leetcode200题。

给你一个由 '1'(陆地)和 '0'(水)组成的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围

示例:

输入:grid = [

["1","1","0","0","0"],

["1","1","0","0","0"],

["0","0","1","0","0"],

["0","0","0","1","1"]

]

输出:3

二、首先介绍一下什么是广度优先搜索

1.先以实例来演示
(1)对图1来说,以A为源点进行广度优先搜索

图3

序列:A B C D E F G H I

(2)对图1来说,以B为源点进行广度优先搜索

图3

序列:B A E F C D I G H

2.操作方法

已知一个图的顶点集合为

顶点的邻接点集合为

首先选定一个起始点

1)、访问顶点

2)、访问完 的所有未被访问的邻接点

3)、依次从这些邻接点(在步骤2中访问的顶点)出发,访问它们的所有未被访问的邻接点; 依此类推,直到图中所有访问过的顶点的邻接点都被访问

可以发现,广度优先搜索类似于树的层次遍历

3.实现方法

广度优先搜索具体怎么实现

广度优先搜索主要用到队列这个数据结构,与之相似的深度优先搜索主要用到栈。

(1)以图2为例

设置两个队列,第一个队列que用来操作BFS,第二个队列Note用来记录边路序列

1).节点A进入队列que,标记已访问,A推入队列Note,已访问节点集合

2).A的所有未访问邻接点(B,C,D)进入队列que,标记已访问,A弹出队列, B,C,D推入队列Note,已访问节点集合

3).B的所有未访问邻接点(E,F)进入队列que,标记已访问,B弹出队列que,E,F推入队列Note, 已访问节点集合

4).C的所有未访问邻接点G进入队列que,标记已访问,C弹出队列que,G推入队列Note, 已访问节点集合

5).D的所有未访问邻接点H进入队列que,标记已访问,D弹出队列que,H推入队列Note, 已访问节点集合

6).E的所有未访问邻接点I进入队列que,标记已访问,E弹出队列que,I推入队列Note, 已访问节点集合

7).F没有未访问的邻接点,F弹出队列que,已访问节点集合

8).G没有未访问的邻接点,G弹出队列que,已访问节点集合

9).H没有未访问的邻接点,H弹出队列que,已访问节点集合

10).I没有未访问的邻接点,I弹出队列que,已访问节点集合

(2)算法具体化

已知一个图的顶点集合为

顶点的邻接点集合为

已访问的节点集合为

这里分别是个取值为1~n的自然数

首先选定一个起始点

1、访问顶点 ,顶点推入队列,加入集合.

2、访问完队头元素() 的所有未被访问的邻接点,并把诸推入队列,放入集合,再把队头元素弹出队列

3、再次访问队头元素(在步骤2中访问的节点的第一个邻接点),访问它的所有未被访问的邻接点,把所有访问到的邻接点推入队列,放入集合,弹出队头元素,依此类推,直到队列变空。

三、BFS的代码实现

1.问题一代码如下

(1).返回的遍历序列是向量的情形,此代码基于图的邻接矩阵

#include<iostream>
#include<queue>
#include<vector>
using namespace std;template<class T>//表示边的变量可以为整数,也可以为字符串,所以在这里使用模板T
class Graph {
public:vector<vector<int>> NeighMatrix;//邻接矩阵vector<T> EdgeList;             //表示点集的向量,可以是整型或字符型,所以这里用模板表示Graph(vector<vector<int>> Matrix, vector<T> edgelist) //利用邻接矩阵和边集对图实例化{NeighMatrix = Matrix;EdgeList = edgelist;}int FirstNeighbour(int node) //定义一个成员函数,用来获取某个节点的首个相邻节点{for (int j = 0; j < NeighMatrix.size(); j++)if (NeighMatrix[node][j] != 0)return j;return -1;}int NextNeighbour(int node, int subnode) //定义一个成员函数,用来获取某个节点在节点subnode后的下一个邻接点{for (int j = subnode + 1; j < NeighMatrix.size(); j++)if (NeighMatrix[node][j] != 0)return j;return -1;}vector<int> BFS(int start) //人为规定起点,返回BFS遍历节点的索引[0~num-1]{queue<int> que;//定义一个队列,用于BFSvector<int> note;//若需要遍历结果作为向量形式的返回值,用note存储遍历结果vector<int> visitmark(NeighMatrix.size(), 0);//访问标记向量,某元素索引i未被访问过时,visitmark[i]=0,否则为1que.push(start);//先把起点推入队列visitmark[start] = 1;//起点被访问cout << "startpoint=" << EdgeList[start] << ",result=";cout << EdgeList[start] << " ";while (que.size()) //循环体进行的条件是队列存在元素{int i = que.front();//把队头元素(节点i)的全部未访问邻接点放到队列中if (FirstNeighbour(i) != -1)//前提条件是队头元素至少存在一个邻接点{if (visitmark[FirstNeighbour(i)] == 0) //若要把该节点推入队列,需要确保该节点未被访问{que.push(FirstNeighbour(i));visitmark[FirstNeighbour(i)] = 1;//节点推入队列,同时标记为已访问cout << EdgeList[FirstNeighbour(i)] << " ";}int j = FirstNeighbour(i);if (j == -1)break;while (NextNeighbour(i, j) != -1) //节点i的邻接节点中,存在下一个与i相邻的节点{if (visitmark[NextNeighbour(i, j)] == 0){que.push(NextNeighbour(i, j));visitmark[NextNeighbour(i, j)] = 1;cout << EdgeList[NextNeighbour(i, j)] << " ";j = NextNeighbour(i, j);//继续迭代,直到节点i的所有相邻节点全部被访问}elsej = NextNeighbour(i, j);//若没有这行代码,有可能进入死循环if (j == -1)break;}}note.push_back(que.front());que.pop();//每次循环找出队头元素的所有未访问邻接点,放到队尾,再删去队头元素,这是一个有限的过程}cout << endl;return note;}
};
int main()
{vector<vector<int>> Matrix;vector<int> subMatrix, edge,ans;int num;cin >> num; //输入邻接矩阵for (int i = 0; i < num; i++) {edge.push_back(i + 1);//这里用1表示第一个节点Matrix.push_back(subMatrix);for (int j = 0; j < num; j++){int ele;cin >> ele;Matrix[i].push_back(ele);}}Graph<int> G = Graph<int>(Matrix, edge);for (int i = 0; i < Matrix.size(); i++)ans = G.BFS(i);return 0;
}
(2).无返回值的情形,同时设定点集用字符A,B,C,…表示

z

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
template<class T>
class Graph {
public:vector<vector<int>> NeighMatrix;//邻接矩阵vector<T> EdgeList;             //表示点集的向量,可以是整型或字符型,所以这里用模板表示Graph(vector<vector<int>> Matrix, vector<T> edgelist) //利用邻接矩阵和边集对图实例化{NeighMatrix = Matrix;EdgeList = edgelist;}int FirstNeighbour(int node) //定义一个成员函数,用来获取某个节点的首个相邻节点{for (int j = 0; j < NeighMatrix.size(); j++)if (NeighMatrix[node][j] != 0)return j;return -1;}int NextNeighbour(int node, int subnode) //定义一个成员函数,用来获取某个节点在节点subnode后的下一个邻接点{for (int j = subnode + 1; j < NeighMatrix.size(); j++)if (NeighMatrix[node][j] != 0)return j;return -1;}void BFS_void(int start) //人为规定起点,返回BFS遍历节点的索引[0~num-1]{queue<int> que;//定义一个队列,用于BFSvector<int> visitmark(NeighMatrix.size(), 0);//访问标记向量,某元素索引i未被访问过时,visitmark[i]=0,否则为1que.push(start);//先把起点推入队列visitmark[start] = 1;//起点被访问cout << "startpoint=" << EdgeList[start] << ",result=";cout << EdgeList[start] << " ";while (que.size()) //循环体进行的条件是队列存在元素{int i = que.front();//把队头元素(节点i)的全部未访问邻接点放到队列中if (FirstNeighbour(i) != -1)//前提条件是队头元素至少存在一个邻接点{if (visitmark[FirstNeighbour(i)] == 0) //若要把该节点推入队列,需要确保该节点未被访问{que.push(FirstNeighbour(i));visitmark[FirstNeighbour(i)] = 1;//节点推入队列,同时标记为已访问cout << EdgeList[FirstNeighbour(i)] << " ";}int j = FirstNeighbour(i);if (j == -1)break;while (NextNeighbour(i, j) != -1) //节点i的邻接节点中,存在下一个与i相邻的节点{if (visitmark[NextNeighbour(i, j)] == 0){que.push(NextNeighbour(i, j));visitmark[NextNeighbour(i, j)] = 1;cout << EdgeList[NextNeighbour(i, j)] << " ";j = NextNeighbour(i, j);//继续迭代,直到节点i的所有相邻节点全部被访问}elsej = NextNeighbour(i, j);//若没有这行代码,有可能进入死循环if (j == -1)break;}}que.pop();//每次循环找出队头元素的所有未访问邻接点,放到队尾,再删去队头元素,这是一个有限的过程}cout << endl;}
};int main()
{vector<vector<int>> Matrix;vector<int> subMatrix;vector<char> edge;int num;cin >> num;//输入邻接矩阵for (int i = 0; i < num; i++) {edge.push_back((char)(65 + i));Matrix.push_back(subMatrix);for (int j = 0; j < num; j++) {int ele;cin >> ele;Matrix[i].push_back(ele);}}Graph<char> G = Graph<char>(Matrix, edge);for (int i = 0; i < Matrix.size(); i++)G.BFS_void(i);return 0;
}

问题一的输入

9
0 1 1 1 0 0 0 0 0
1 0 0 0 1 1 0 0 0
1 0 0 1 0 0 0 1 0
1 0 1 0 0 0 0 1 1
0 1 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 1 1 0 0 0 0 0
0 0 0 1 0 0 0 0 0

问题一(1)的运行结果

startpoint=1,result=1 2 3 4 5 6 8 9 7
startpoint=2,result=2 1 5 6 3 4 7 8 9
startpoint=3,result=3 1 4 8 2 9 5 6 7
startpoint=4,result=4 1 3 8 9 2 5 6 7
startpoint=5,result=5 2 7 1 6 3 4 8 9
startpoint=6,result=6 2 1 5 3 4 7 8 9
startpoint=7,result=7 5 2 1 6 3 4 8 9
startpoint=8,result=8 3 4 1 9 2 5 6 7
startpoint=9,result=9 4 1 3 8 2 5 6 7

问题一(2)的运行结果

0

startpoint=A,result=A B C D E F H I G
startpoint=B,result=B A E F C D G H I
startpoint=C,result=C A D H B I E F G
startpoint=D,result=D A C H I B E F G
startpoint=E,result=E B G A F C D H I
startpoint=F,result=F B A E C D G H I
startpoint=G,result=G E B A F C D H I
startpoint=H,result=H C D A I B E F G
startpoint=I,result=I D A C H B E F G

2.问题二的分析

这个题和上一题的相同之处在于,可以使用BFS的思想,找出图中的一个陆地点,以这个点为中心进行广度优先搜索,此时,若某个节点被访问,直接把这个节点所在位置的元素由1变为0,直到搜索不到陆地,则此时陆地数量+1,为了后续岛屿的寻找,把这个陆地上的所有点变为0,同时继续向右或者向下找陆地点,重复这个过程

代码如下:

岛屿数量问题的BFS代码,leetcode击败了65%的C++用户,若想在leetcode运行需要去掉main函数·

#include<vector>
#include<queue>
#include<iostream>
using namespace std;class Solution {
public:class Node {public:int x;int y;Node(int xx, int yy) {x = xx; y = yy;}};int numIslands(vector<vector<char>>& grid) {vector<vector<int>> dir = { {1,0},{-1,0},{0,1},{0,-1} };//定义4个方向queue<Node> que;//BFS所用的队列int cnt = 0;//计数器int ii = 0, jj = 0;int xlen = grid.size();int ylen = grid[0].size();while (ii < xlen && jj < ylen) {if (grid[ii][jj] == '1') //第ii行jj列的点是陆地{grid[ii][jj] = '0';Node start=Node(ii,jj);que.push(start);int i = ii, j = jj;while (que.size()) {i = que.front().x;j = que.front().y;for (int m = 0; m < 4; m++) //把队头点的相邻陆地节点全部找出{int xx = i + dir[m][0];int yy = j + dir[m][1];if (xx < 0 || xx >= xlen || yy < 0 || yy >= ylen)continue;//若移动点越界,立刻跳过本次循环if (grid[xx][yy] == '1')//说明此处还是陆地{Node point = Node(xx, yy);que.push(point);grid[xx][yy] = '0';//为防止重复访问,此处变为0}}que.pop();//grid[ii][jj]四周的点全部被推入队列,此时这个点弹出队}cnt += 1;}if (jj < ylen - 1)jj += 1;else{ii += 1; jj = 0;}}return cnt;}
};
int main()
{vector<vector<char>> island{ {'1','1','0','0','0' }, { '1','1','0','0','0' }, { '0','0','1','0','0' }, { '0','0','0','1','1' } };Solution a;cout << a.numIslands(island);return 0;
}

广度优先搜索以及C++实现相关推荐

  1. [C] 层层递进——C语言实现广度优先搜索

    以防万一有人想不开要做染色的题呢?比如我. 广度优先搜索 如何实现一个广度优先搜索 广搜(bfs)是一个层层递进的概念,与深搜的不撞南墙不回头不同,广搜更像一个感染的过程,一个点只能感染到它周边的点. ...

  2. python扫雷 广度优先_Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper)...

    Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tre ...

  3. 初识广度优先搜索与解题套路

    作者 | P.yh 来源 | 五分钟学算法 初识广度优先搜索 在讲解广度优先搜索之前,我们来看看几个常见的数据结构,链表.树.图. 先来看看其中比较简单的数据结构 - 链表,它和数组类似,也是一个线性 ...

  4. matlab bfs函数,matlab练习程序(广度优先搜索BFS、深度优先搜索DFS)

    如此经典的算法竟一直没有单独的实现过,真是遗憾啊. 广度优先搜索在过去实现的二值图像连通区域标记和prim最小生成树算法时已经无意识的用到了,深度优先搜索倒是没用过. 这次单独的将两个算法实现出来,因 ...

  5. networkx 有向图强连通_leetcode刷题(四):搜索(深度优先搜索,广度优先搜索)拓扑排序,强连通分量...

    在开始今天的话题之前,我们先了解一个概念,什么是图的遍历? 图的遍历就是从图中某一点出发访遍图中其余剩余定点,且每个顶点仅被访问一次,这个过程叫做图的遍历. 图的遍历主要被分为深度优先遍历和广度优先遍 ...

  6. LeetCode-笔记-199. 二叉树的右视图——BFS广度优先搜索

    LeetCode-笔记-199. 二叉树的右视图 199. 二叉树的右视图 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值. 示例: 输入: [1,2,3,n ...

  7. 根据邻接表求深度优先搜索和广度优先搜索_深度优先搜索/广度优先搜索与java的实现...

    度:某个顶点的度就是依附于该顶点的边的个数 子图:一幅图中所有边(包含依附边的顶点)的子集 路径:是由边顺序连接的一系列定点组成 环:至少含有一条边且终点和起点相同的路径 连通图:如果图中任一个到另一 ...

  8. 图的遍历——广度优先搜索(Breadth First Search)

    2019独角兽企业重金招聘Python工程师标准>>> 1.广度优先搜索遍历类似于树的按层次遍历的过程. 假设从图中某顶点V出发,在访问了V之后依次访问V的各个未曾访问过得邻接点,然 ...

  9. 地牢逃脱(BFS(广度优先搜索))

    题目描述 给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (x0 , y0 ) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一 ...

  10. 用BFS(广度优先搜索queuelist)算法解决农夫过河问题

    用BFS(广度优先搜索queue&&list)算法解决农夫过河问题 一.问题需求分析 一个农夫带着一只狼.一只羊和一棵白菜,身处河的南岸.他要把这些东西全部运到北岸.问题是他面前只有一 ...

最新文章

  1. NS3_Tutorial 中文版: 第一章 简介 第二章 资源
  2. php设置低于设定值不能用,php memory limit怎么设置不限制
  3. python requests 报错 Connection aborted ConnectionResetError RemoteDisconnected 解决方法
  4. renpy 如何执行2个action_如何解决工作中遇到问题丨2个思考方式、2个技巧和1个解决系统...
  5. java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的
  6. Geoserver怎样切割离线瓦片地图
  7. dart和python混编,Flutter与iOS混编(一)
  8. Asp.net Ajax 客户端页面生命周期原生事件
  9. dubbo调用超时回滚_微服务痛点基于Dubbo + Seata的分布式事务(AT模式)
  10. Jscript中文变量乱码,又一次中招 _
  11. Windows | 管理员权限打开CMD 快捷键
  12. 软件测试组工作计划,测试组长工作计划(共10篇).doc
  13. 如何获取到电脑所连接Wifi的密码
  14. java游戏实例_Java游戏俄罗斯方块的实现实例
  15. VSCode(Visual Studio Code)整合Git
  16. XSKY新一代分布式文件系统XGFS揭秘——元数据服务
  17. 玩转Kaggle:Classify Leaves(叶子分类)——模型设计与训练
  18. springboot+JRebel--插件实现热部署
  19. 实习生两大杀手之一:Git 引入
  20. 在TI DSP开发板中烧写Flash程序

热门文章

  1. 零基础入门金融风控之贷款违约预测—赛题理解
  2. Kooboo中怎么新增一个关联的Details 动态页面。
  3. 利用sox 做通道转换
  4. SystemTap介绍
  5. Workfine新手入门:如何创建第一张表单
  6. 在阿里云安装redis
  7. 10个获得美好生活的小窍门
  8. Navicat如何连接远程服务器的MySQL
  9. tomcat后台多种姿势getshell
  10. 计算机页面不稳定怎么办,我的系统不稳定该怎么办啊?为什么会这样啊?