[数据结构]广度优先搜索算法(Breadth-First-Search,BFS)
广度优先搜索的概念
广度优先搜索(BFS)类似于二叉树的层序遍历算法,它的基本思想是:首先访问起始顶点v,然后由v出发,依次访问v的各个未被访问过的邻接顶点w1,w2,w3….wn,然后再依次访问w1,w2,…,wi的所有未被访问过的邻接顶点,再从这些访问过的顶点出发,再访问它们所有未被访问过的邻接顶点….以此类推,直到途中所有的顶点都被访问过为止。类似的想法还将应用与Dijkstra单源最短路径算法和Prim最小生成树算法。(这个过程我觉得可以举个这样的例子来理解:比如要从你开始介绍你的家人,可以先从你开始,然后一个一个介绍和你有直接血缘关系的这一层亲属(爸爸妈妈儿子女儿),当把你所有的这些第一层亲属全都遍历完之后再从你的妈妈开始遍历(也可以从爸爸或儿子),把你妈妈的有直接血缘关系的亲戚先遍历一遍,然后再从爸爸开始,以此类推,直到全部都遍历完成)。
广度优先搜索是一种分层的查找过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样有回退的情况(另一篇博客会介绍),因此它不是一个递归的算法,为了实现逐层的访问,算法必须借助一个辅助队列并且以非递归的形式来实现。
算法伪代码
其伪代码如下:
bool visited[MAX_VERTEX_NUM];//访问数组,也就是顶点个数
void BFSTraverse(Graph G)
//外层的函数,为准备实现遍历做一些准备工作。
{
for(int i=0;i<G.vexnum;++i)
visited[i]=false;//先将所有的顶点都设置为没有被访问过
InitQueue(Q);//初始化辅助队列方便遍历顶点
for(int i=0;i<G.vexnum;++i)
if(!visited[i])
BFS(G,i);
//外层循环使用if语句来调用BFS的原因是为了防止有的顶点它不能从初始顶点出发而遍历到,所以这里需要一个完全的循环来避免这种极端情况。
}
void BFS(Graph G,int v)
//从顶点v出发,广度优先遍历图G,算法借助了一个辅助队列Q
visit(v);//visit函数访问这个顶点的信息
visited[v]=true;//访问过了这个顶点之后就将这个顶点设置为已访问,即true
Enqueue(Q,v);//将顶点v入队列,这样就可以从队列中出队并访问它的相邻顶点
while(!isEmpty(Q)){
DeQueue(Q,v);//将队头的元素出队列存储在v
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))//这一步是检查v的所有邻接顶点
if(!visited[w]){
visit(w);
visited[w]=true;
EnQueue(Q,w);
//如果w没有被访问过,那么访问这个顶点,并把它入队
}
}
实例以及解析
假设从a顶点开始访问,a先入队。此时队列非空,取出队头元素a,由于b,c和a直接相邻且未被访问过,于是依次访问b,c,并且b,c依次入队。队列非空,取出队头元素b,依次访问与b相邻且未被访问的顶点d,e,并且将d,e入队(注意:a与b也邻接,但是a已经访问过,就不会再访问了)。此时队列非空,取出队头元素c,访问与c邻接且未被访问过的顶点f,g,并且将f,g入队。此时,取出队头元素d,但与d邻接且为被访问的顶点为空,故不再进行任何操作,继续取出对头元素e,将h入队….当最后取出队头元素h后,队列为空,从而循环自动跳出,遍历的结果为abcdefgh。
BFS算法性能分析
无论是邻接表还是邻接矩阵的存储访问,BFS算法都需要借助一个辅助队列Q,n个顶点都需要入队依次,在最坏的情况下,空间复杂度为O(|V|)。
当采用邻接表存储方式时,每个顶点均需要搜索依次(或入队依次),故时间复杂度为O(|V|),再搜索任一顶点时,每条边至少访问依次,故时间复杂度为O(|E|),算法的总时间复杂度为O(|V|+|E|);当采用邻接矩阵存储方式的时候,查找每个顶点的邻接点所需时间为O(|V|),故算法总的时间复杂度为O(|V|²)。
BFS算法求单源最短路径问题
如果图G=(V,E)为非带权图。定义从顶点u到顶点v的最短路径d(u,v)为从u到v的任何路径中最少的边数;如果从u到v没有通路,则d(u,v)=∞。
使用BFS,我们可以求解一个满足上述定义的非带权图的单源最短路径问题,这是由广度优先搜索总是按照距离由近到远来遍历图中每个顶点的性质决定的(这让我想到:在2d游戏中计算两个位置的最短路径是否可以采用BFS算法来求出呢?)
BFS算法求解单源最短路径问题的算法如下:
void BFS_MIN_Distance(Graph G,int u){
//d[i]表示从u到i结点的最短路径
for(i=0;i<G.vexnum;++i)
d[i]=∞; //初始化路径长度
visited[u]=true;
d[u]=0;
while(!isEmpty(Q)){
DeQueue(Q,u);
for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
if(!visited[w]){//w为u未曾访问的邻接顶点
visited[w]=true;//设为已经访问
d[w]=d[u]+1;//路径长度+1
EnQueque(Q,w);//w顶点入队
}
}
}
[数据结构]广度优先搜索算法(Breadth-First-Search,BFS)的更多相关文章
- 广度优先搜索(Breadth First Search, BFS)
广度优先搜索(Breadth First Search, BFS) BFS算法实现的一般思路为: // BFS void BFS(int s){ queue<int> q; // 定义一个 ...
- 【2018.07.30】(广度优先搜索算法/队列)学习BFS算法小记
一些BFS参考的博客: https://blog.csdn.net/ldx19980108/article/details/78641127 https://blog.csdn.net/u011437 ...
- ZH奶酪:【数据结构与算法】搜索之BFS
1.目标 通过本文,希望可以达到以下目标,当遇到任意问题时,可以: 1.很快建立状态空间: 2.提出一个合理算法: 3.简单估计时空性能: 2.搜索分类 2.1.盲目搜索 按照预定的控制策略进行搜索, ...
- python 递归深度优先搜索与广度优先搜索算法模拟实现
一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件2.找出这一次和上一次关系3.假设当前 ...
- python 递归,深度优先搜索与广度优先搜索算法模拟实现
一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件 2.找出这一次和上一次关系 3.假设 ...
- AI广度优先搜索算法,项目实战北京地图/贪心学院
广度优先搜索算法详解地铁路线 北京很大,附上地铁图,不要迷路!!! 作为一个程序员,在北京,你很有可能住在回龙观地区,经常从龙泽上地铁,然后畅游北京. 当有一天,你老家的朋友来北京了,希望你能够带她去 ...
- [数据结构]深度优先搜索算法(Depth-First-Search,DFS)
深度优先搜索算法的概念 与广度优先搜索算法不同,深度优先搜索算法类似与树的先序遍历.这种搜索算法所遵循的搜索策略是尽可能"深"地搜索一个图.它的基本思想如下:首先访问图中某一个起始 ...
- javascript实现的图数据结构的广度优先 搜索(Breadth-First Search,BFS)和深度优先搜索(Depth-First Search,DFS)
最后一例,搞得快.三天之内走了一次.. 下一步,面象对像的javascript编程. function Dictionary(){ var items = {}; this.has = functio ...
- 数据结构之 图论---基于邻接矩阵的广度优先搜索遍历(输出bfs遍历序列)
数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索( ...
随机推荐
- Vue中使用Switch开关用来控制商品的上架与下架情况、同时根据数据库商品的状态反应到前台、前台修改商品状态保存到数据库
一般后台对商品的信息管理.包含商品的上架与下架.为了提高用户的体验.将商品上下架的操作做成开关的形式.同时后台数据库中保存的商品状态能够根据开关状态改变. 1.效果展示 这种效果:== 当开关是开启状 ...
- java 入土--集合详解
java 集合 集合是对象的容器,实现了对对象的常用的操作,类似数组功能. 和数组的区别: 数组长度固定,集合长度不固定 数组可以存储基本类型和引用类型,集合只能存储引用类型 使用时需要导入类 Col ...
- 齐博x1 万能fun 调用任意数据表 任意字段就是这么任性调用
列举了几个常用的查询进行简单封装,虽然系统也有内置的但是很多人不大会就二次封装简化了一下. 这里只封装了一个条件 多个条件的自己再封装或者用标签解决比较好 这里只是说fun可以万能调用 1获取任意表的 ...
- 还在用双层for循环吗?太慢了
前情提要 我们在开发中经常碰到这样的场景,查出两个 list 集合数据,需要根据他们相同的某个属性为连接点,进行聚合.但是平时我们使用的时候关注过性能吗?下面让我们一起来看看它的表现如何. 来个例子 ...
- 抓包分析 TCP 握手和挥手
前言 首先需要明确的是 TCP 是一个可靠传输协议,它的所有特点最终都是为了这个可靠传输服务.在网上看到过很多文章讲 TCP 连接的三次握手和断开连接的四次挥手,但是都太过于理论,看完感觉总是似懂非懂 ...
- 本人常用的sed命令用法
如果使用sed命令修改文件,需要为sed命令指定[-i]选项(i,insert表示插入指令),下面是本人常用到的几种场景: 1. 在文件最后一行的下一行添加配置 如:在配置文件/etc/profile ...
- Git配置和使用?Git你真的会用么?Git与SVN的主要区别
1.Git环境配置 在学习Git之前,首先要知道什么是版本控制 1.1 版本控制:版本迭代.新的版本!版本管理器 版本控制是开发过程中用于管理我们的文件.目录或工程内容的修改内容,查看修改历史记 ...
- 【项目】AtCoder for Chinese
前排提示:Github 内容搭配梯子食用效果更佳( 项目地址 网页 插件安装 Join us or Give us a star ! 注:因内容迁移,下列链接暂时失效(用空再搬一遍)qwq Trans ...
- XTDrone和PX4学习期间问题记录(一)
XTDrone和PX4学习期间问题记录(一) Written By PiscesAlpaca 前言: 出现问题可以去官方网站http://ceres-solver.org/index.html查看文档 ...
- shell文件报错syntax error near unexpected token '$'\r''
本来跑的好好得一个文件,在windows下修改了,然后移植到linux就报错了. 找了一圈以下是解决方案: 这种情况发生的原因是因为你所处理的文件换行符是dos格式的"\r\n" ...