BFS算法

上一篇文章讲解了DFS深度优先遍历的算法,我们说 DFS 顾名思义DEEPTH FIRET,以深度为第一标准来查找,以不撞南墙不回头的态度来发掘每一个点,这个算法思想get到了其实蛮简单。那么 BFS 和DFS有什么相同点和不同点呢?

我觉得有一种比喻对于 DFS 和 BFS 从方法论的角度解释很到位,DFS 就像是小明要在家里找到钥匙,因为对位置的不确定,所以一间一间的来找,深度遍历能确保小明走过所有的屋子。而 BFS 像是近视的小明的眼镜掉在了地上,小明肯定是先摸索离手比较近的位置,然后手慢慢向远方延伸,直至摸到眼镜,像是以小明为中心搜索圈不断扩大的过程。所以如果说 DFS 从遍历的层次结构上类似树的先序遍历,那么BFS算法按照里外顺序逐渐增加深度的做法,就像极了朴素的层次遍历,例如:

把左图拉平,按照层序把结点排列下来,各节点的连接关系并没有变,图结构没有发生变化,但是这时,我们从A出发,按层序遍历可以得到顺序是 A B F C I G E D H

结合上一篇文章的 DFS ,我们可以发现这两种算法的区别在每一个点上都能得以体现,比如 A 点,DFS 鼓励结点向着一个方向冲,BFS 则会在一个点上按照顶点下标次序遍历完所有没有访问过的结点,比如A点遍历完,马上开始扫描,如果 B F这两个点没有被宠幸过,那么一定要翻完 B、F 这两个点的牌子之后,才会继续访问第二层,即把A点相连的结点全部遍历完成才行,当然到了第二层 发现 B、F 早就被A安排过了,就不再进入这两个点的循环,后面的一样,这里就不再赘述。

我们回忆一下DFS算法,DFS沿着一个方向走最后是要走回头路的,因为它迟早会遍历到一个所有分支都被访问过的结点,那么要走回头路意味着我们实现 DFS 时应该选择后进先出的栈结构,而现在的 BFS 算法是每经过一个点就会遍历所有没访问过的点,同时,一个点如果已经访问完,那么它就没有利用价值了,所以应该使用队列先进先出的特点

这里是图形演示:

下面我们来看代码实现:

这是邻接矩阵实现 BFS 算法,结构定义见上一篇文章

void BFS(MGraph *G)
{
int i,j;
Queue Q;
InitQueue(&Q);
for(i = ; i < G.numVertexes;i++)
{
visited[i] = FALSE;
}
for(i = ;i < G.numVertexes;i++)
{
if(!visited[i])
{
visited[i] = TRUE;
printf("%c",&G.vexs[i]);
EnQueue(&Q,i);
while(!QueueEmpty(Q))
{
DeQueue(&Q,&i);
for(j = ;j < G.numVertexes;j++)
{
while(G.arc[i][j] == && !visited[j])
{
visited[j] = TRUE;
printf("%c",G.vexs[j]);
EnQueue(&Q,j);
}
}
}
}
}
}

这是邻接表实现的代码:

void BFS(GraphAdjList GL)
{
int i;
Queue Q;
EdgeNode *p;
InitQueue (&Q);
for(i = ;i < GL->shuliang;i++)
{
visited[i] = FALSE;
}
for(i = ;i < GL->shuliang;i++)
{
if(!visited[i])
{
visited[i] = TURE;
printf("%c",GL->adjlist[i].data);
EnQueue(&Q,i);
while(!QueueEmpty(Q))
{
DeQueue(&Q,&i);
p = GL->adjlist[i].firstedge;
while(p)
{
if(!visited[p -> adjvex])
{
visited[p -> adjvex] = TRUE;
printf("%c",GL->adjlist[p -> adjvex].data);
EnQueue(&Q,p->adjvex);
}
p = p -> next;
}
}
}
} }

个人感觉代码蛮好懂,这一块感觉需要多多思考,广度优先和深度优先小到日常生活,大到数据模型,有着广泛的作用,而这篇文章中的两种方法,因为都要遍历整张图,所以其算法时间复杂度相同,所以对于全图遍历并没有什么明确选择的优势,而如果目的在于尽快地找到目的点,那么深度优先更占优势;而如果是不断扩大遍历范围,寻找相对最优解则是广度优先看起来更划算。算法就到这里,经验和思路只能靠大家自己在实践中多多总结,得到自己使用的一套方法。

(原创)BFS广度优先算法,看完这篇就够了的更多相关文章

  1. 关于 Docker 镜像的操作,看完这篇就够啦 !(下)

    紧接着上篇<关于 Docker 镜像的操作,看完这篇就够啦 !(上)>,奉上下篇 !!! 镜像作为 Docker 三大核心概念中最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌 ...

  2. MAC上的爬虫软件怎么选?看完这篇就够了

    在上一篇文章:网络爬虫软件哪个好用? 中,我们介绍了目前市面上比较成熟好用的网络爬虫软件, 但是其中有些不能在MAC上使用,因此今天这篇文章我们单独介绍一下在MAC操作系统中有哪些好用的爬虫软件,给大 ...

  3. 还不会ida*算法?看完这篇或许能理解点。

    IDA* 算法分析 IDA* 本质上就是带有估价函数和迭代加深优化的dfs与,A * 相似A *的本质便是带 有估价函数的bfs,估价函数是什么呢?估价函数顾名思义,就是估计由目前状态达 到目标状态的 ...

  4. 研究分布式唯一ID生成,看完这篇就够

    很多大的互联网公司数据量很大,都采用分库分表,那么分库后就需要统一的唯一ID进行存储.这个ID可以是数字递增的,也可以是UUID类型的. 如果是递增的话,那么拆分了数据库后,可以按照id的hash,均 ...

  5. HTML教程(看完这篇就够了)

    HTML教程 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言.您可以使用 HTML 来建立自己的 WEB 站点,HTML 运 ...

  6. 关于 Docker 镜像的操作,看完这篇就够啦 !(上)

    文章首发于微信公众号: 小哈学Java 镜像作为 Docker 三大核心概念中,最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌握的.本文将带您一步一步,图文并重,上手操作来学习它. 目录 ...

  7. 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?

    简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...

  8. [转帖]看完这篇文章,我奶奶都懂了https的原理

    看完这篇文章,我奶奶都懂了https的原理 http://www.17coding.info/article/22 非对称算法 以及 CA证书 公钥 核心是 大的质数不一分解 还有 就是 椭圆曲线算法 ...

  9. Mysql快速入门(看完这篇能够满足80%的日常开发)

    这是一篇mysql的学习笔记,整理结合了网上搜索的教程以及自己看的视频教程,看完这篇能够满足80%的日常开发了. 菜鸟教程:https://www.runoob.com/mysql/mysql-tut ...

随机推荐

  1. 【luogu P3371 单源最短路径】 模板 dij + heap

    题目链接:https://www.luogu.org/problemnew/show/P3371#sub 堆优化迪杰斯特拉,留着以后复习用 #include <iostream> #inc ...

  2. video object detection

    先说一下,我觉得近两年最好的工作吧.其他的,我就不介绍了,因为我懂得少. 微软的jifeng dai的工作. Deep Feature Flow   github: https://github.co ...

  3. 数据流管理:redux

    redux和react是两个独立的库,所以redux并不是非用不可,是在Flux框架的基础上改进的一个框架,所以一鸣惊人 redux的三大基本原则 唯一的数据源(single source of tr ...

  4. html+css让网页自动适应手机屏幕

    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scal ...

  5. redis的安装和启动linux环境

    启动客户端连接redis服务,redis-cli -p(端口) -h(登录的服务的ip地址);不添加任何参数和选项直接使用redis-cli将会默认登录6379,默认使用ip 127.0.0.1#re ...

  6. 零基础Python知识点回顾(二)

    开始了,继续说!字符串替换,就是预留着空间,后边再定义要填上什么,这种叫字符串格式化,其有两种方法: %    和 format %s  就是一个占位符,这个占位符可以被其它的字符串代替 >&g ...

  7. HTML表格和表单

    <table>格式: 注意:1. 合并单元格:COLSPAN(跨列)ROWSPAN(跨行) 2.cellspacing属性定义单元格之间的间距(以像素为单位). cellpadding属性 ...

  8. iOS之UIKeyboardType 11种键盘图片展示

    UIKeyboardTypeDefault      UIKeyboardTypeASCIICapable  ==  UIKeyboardTypeAlphabet      UIKeyboardTyp ...

  9. 2019年第十届蓝桥杯c++A组java/c++组题解

    #include<iostream> #include<vector> using namespace std; vector <int > vec; long l ...

  10. 针对 npm ERR! cb() never called! 问题

    在开发项目安装依赖时(npm install) 往往会报  npm ERR! cb()never called!的错误 如图: 解决方法: 一.首先要以管理员模式打开cmd清除你的npm缓存 : np ...