一、重拾关键

宽度优先搜索,也有称为广度优先搜索,简称BFS。类似于树的按层次遍历的过程。

初始状态:图G所有顶点均未被访问过,任选一点v。

遍历过程:假设从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程中以v为起始点,由近至远,依次访问和v有路径相通且路径长度为1,2,…的顶点。

二、算法过程

以如下图的无向图G4为例,进行图的宽度优先搜索:

假设从顶点v1出发进行搜索,首先访问v1和v1的邻接点v2和v3,然后依次访问v2的邻接点v4和v5及v3的邻接点v6和v7,最后访问v4的邻接点v8。由于这些顶点的邻接点均已被访问,并且图中所有顶点都被访问,由些完成了图的遍历。得到的顶点访问序列为:

和深度优先搜索类似,在遍历的过程中也需要一个访问标志数组。并且,为了顺次访问路径长度为2、3、…的顶点,需附设队列以存储已被访问的路径长度为1、2、… 的顶点。

三、代码实现

邻接矩阵做存储结构时,广度优先搜索的代码如下。

/*    图的BFS遍历    */
//邻接矩阵形式实现
//顶点从1开始
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 105; //最大顶点数
typedef int VertexType; //顶点类型
bool vis[maxn]; struct Graph{ //邻接矩阵表示的图结构
VertexType vex[maxn]; //存储顶点
int arc[maxn][maxn]; //邻接矩阵
int vexnum,arcnum; //图的当前顶点数和弧数
}; void createGraph(Graph &g) //构建有向网g
{
cout<<"请输入顶点数和边数:";
cin>>g.vexnum>>g.arcnum; //构造顶点向量
cout<<"请依次输入各顶点:\n";
for(int i=1;i<=g.vexnum;i++){
scanf("%d",&g.vex[i]);
} //初始化邻接矩阵
for(int i=1;i<=g.vexnum;i++){
for(int j=1;j<=g.vexnum;j++){
g.arc[i][j] = 0;
}
} //构造邻接矩阵
VertexType u,v; //分别是一条弧的弧尾(起点)和弧头(终点)
printf("每一行输入一条弧依附的顶点(空格分开):\n");
for(int i=1;i<=g.arcnum;i++){
cin>>u>>v;
g.arc[u][v] = g.arc[v][u] = 1;
}
} //邻接矩阵的宽度遍历操作
void BFSTraverse(Graph g)
{
queue<int> q; //声明队列q
for(int i=1;i<=g.vexnum;i++){
vis[i] = false;
}
for(int i=1;i<=g.vexnum;i++){ //对每个顶点做循环
if(!vis[i]){
vis[i] = true;
printf("%d\t",g.vex[i]);
q.push(i); //将此节点入队列
while(!q.empty()){
int m = q.front();
q.pop(); //出队列,值已赋给m
for(int j=1;j<=g.vexnum;j++){
if(g.arc[m][j]==1 && !vis[j]){ //如果顶点j是顶点i的未访问的邻接点
vis[j] = true;
printf("%d\t",g.vex[j]);
q.push(j); //将顶点j入队列
}
} }
}
} } int main()
{
Graph g;
createGraph(g);
BFSTraverse(g);
return 0;
}

我的代码2:

 int n, m;
int graph[][];
bool vis[];
queue<int> q; void init()
{
memset(map,,sizeof(map));
memset(vis,,sizeof(vis));
while(!q.empty()) q.pop();
} void BFS(int u)
{
vis[u] = ;
cout<<u<<"\t";
q.push(u);
while(!q.empty()){
int p = q.front();
q.pop();
for(int i=;i<=n;i++){
if(!vis[i] && graph[p][i]==){
q.push(i);
cout<<i<<"\t";
vis[i] = ;
}
}
}
} void read()
{
init();
cin>>n>>m;
for(int i=;i<=m;i++){
int u, v;
cin>>u>>v;
graph[u][v] = graph[v][u] = ;
}
for(int i=;i<=n;i++){
if(!vis[i])
BFS(i);
}
cout<<endl;
} int main()
{
read();
return ;
}

对于邻接表的广度优先遍历,代码与邻接矩阵差异不大, 代码如下。

//邻接表的广度遍历算法
void BFSTraverse(GraphList g)
{
int i;
EdgeNode *p;
Queue q;
for(i = 0; i < g.numVertexes; i++)
{
visited[i] = FALSE;
}
InitQueue(&q);
for(i = 0; i < g.numVertexes; i++)
{
if(!visited[i])
{
visited[i] = TRUE;
printf("%c ", g.adjList[i].data); //打印顶点,也可以其他操作
EnQueue(&q, i);
while(!QueueEmpty(q))
{
int m;
DeQueue(&q, &m);
p = g.adjList[m].firstedge; 找到当前顶点边表链表头指针
while(p)
{
if(!visited[p->adjvex])
{
visited[p->adjvex] = TRUE;
printf("%c ", g.adjList[p->adjvex].data);
EnQueue(&q, p->adjvex);
}
p = p->next;
}
}
}
}
}

分析上述算法,每个顶点至多进一次队列。遍历图的过程实质是通过边或弧找邻接点的过程,因此广度优先搜索遍历图的时间复杂度和深度优先搜索遍历相同,两者不同之处仅仅在于对顶点访问的顺序不同。

四、沙场练兵

题目一、迷宫问题

数据结构7——BFS的更多相关文章

  1. 【暑假】[基本数据结构]根据BFS与DFS确定树

    UVa10410 Tree Reconstruction 算法:根据BFS构造pos数组以区分关系,在此基础上对DFS序列操作.注:栈中存父结点,栈顶是最优先的父结点. 代码如下: #include& ...

  2. 用js来实现那些数据结构16(图02-图的遍历)

    上一篇文章我们简单介绍了一下什么是图,以及用JS来实现一个可以添加顶点和边的图.按照惯例,任何数据结构都不可或缺的一个point就是遍历.也就是获取到数据结构中的所有元素.那么图当然也不例外.这篇文章 ...

  3. Uva 1599 最佳路径

    题目链接:https://uva.onlinejudge.org/external/15/1599.pdf 题意: 保证在最短路的时候,输出字典序最小的路径. 方法: 路径上有了权值,可以利用图论的数 ...

  4. Codeforces 605D - Board Game(树状数组套 set)

    Codeforces 题目传送门 & 洛谷题目传送门 事实上是一道非常容易的题 很容易想到如果 \(c_i\geq a_j\) 且 \(d_i\geq b_j\) 就连一条 \(i\to j\ ...

  5. 数据结构 《2》----基于邻接表表示的图的实现 DFS(递归和非递归), BFS

    图通常有两种表示方法: 邻接矩阵 和 邻接表 对于稀疏的图,邻接表表示能够极大地节省空间. 以下是图的数据结构的主要部分: struct Vertex{ ElementType element; // ...

  6. 数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)

    数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边& ...

  7. 数据结构和算法总结(一):广度优先搜索BFS和深度优先搜索DFS

    前言 这几天复习图论算法,觉得BFS和DFS挺重要的,而且应用比较多,故记录一下. 广度优先搜索 有一个有向图如图a 图a 广度优先搜索的策略是: 从起始点开始遍历其邻接的节点,由此向外不断扩散. 1 ...

  8. 数据结构与算法之PHP用邻接表、邻接矩阵实现图的广度优先遍历(BFS)

    一.基本思想 1)从图中的某个顶点V出发访问并记录: 2)依次访问V的所有邻接顶点: 3)分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,直到图中所有已被访问过的顶点的邻接点都被访问到. 4) ...

  9. [数据结构]图的DFS和BFS的两种实现方式

    深度优先搜索 深度优先搜索,我们以无向图为例. 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似. 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发, ...

随机推荐

  1. Vue+Electron实现简单桌面应用

    之前一直使用C#编写桌面应用,也顺带写一些Web端应用.最近在看node时发现常用的vscode是用electron编写的,一种想吃螃蟹的念头就涌了上来. 在网上找了找electron的资料,也研究了 ...

  2. 原生js的常见封装

    )); } ;;;;]){                 ];                 ] = ;;;,)     ,)     ,)     ,)         ,)         , ...

  3. sencha inspector(调试工具)

    Sencha Inspector 一:安装sencha inspector 使用Sencha Inspector下载Ext JS试用版(可在此处获得). 下载后,双击下载的文件以启动安装程序,然后按照 ...

  4. Java源码解析——集合框架(三)——Vector

    Vector源码解析 首先说一下Vector和ArrayList的区别: (1) Vector的所有方法都是有synchronized关键字的,即每一个方法都是同步的,所以在使用起来效率会非常低,但是 ...

  5. 浅谈C#实现Web代理服务器的几大步骤

    代理服务程序是一种广泛使用的网络应用程序.代理程序的种类非常多,根据协议不同可以分成HTTP代理服务程序.FTP代理服务程序等,而运行代理服务程序的服务器也就相应称为HTTP代理服务器和FTP代理服务 ...

  6. 数据分析处理库Pandas——索引进阶

    Series结构 筛选数据 指定值 备注:查找出指定数值的索引和数值. 逻辑运算 备注:查找出值大于2的数据. 复合索引 DataFrame结构 显示指定列 筛选显示 备注:值小于0的显示原值,否则显 ...

  7. centos编译安装rabbitmq

    安装环境 [root@VM_12_50_centos rabbitmq]# uname -a Linux VM_12_50_centos 3.10.0-514.21.1.el7.x86_64 #1 S ...

  8. 区分Oracle的数据库,实例,服务名,SID

    文章摘自:http://www.zhetao.com/content240 感谢分享O(∩_∩)O~ 在实际的开发应用中,关于Oracle数据库,经常听见有人说建立一个数据库,建立一个Instance ...

  9. Linux使用imagemagick的convert命令压缩图片,节省服务器空间

    1,安装imagemagick yum install ImageMagick 2,获取图片 find ./ -regex '.*\(jpg\|JPG\|png\|jpeg\)' -size +500 ...

  10. gitk中文乱码问题处理

    执行了 git config --global gui.encoding utf- 查看 %USERPROFILE%\.gitconfig 文件中也有 [gui] encoding = utf-8 在 ...