(原创)BFS广度优先算法,看完这篇就够了

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 = 0; i < G.numVertexes;i++)
    {
        visited[i] = FALSE;
    }
    for(i = 0;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 = 0;j < G.numVertexes;j++)
                {
                    while(G.arc[i][j] == 1 && !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 = 0;i < GL->shuliang;i++)
    {
        visited[i] = FALSE;
    }
    for(i = 0;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;
                }
            }
        }
    }

}

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

原文地址:https://www.cnblogs.com/yx1999/p/10355964.html

时间: 2024-08-29 11:15:37

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

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

原文:关于 Docker 镜像的操作,看完这篇就够啦 !(下) 紧接着上篇<关于 Docker 镜像的操作,看完这篇就够啦 !(上)>,奉上下篇 !!! 镜像作为 Docker 三大核心概念中最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌握的.本文将带您一步一步,图文并重,上手操作来学习它. 目录: 一.Docker 删除镜像 1.1 通过标签删除镜像 1.2 通过 ID 删除镜像 1.3 删除镜像的限制 1.4 清理镜像 二.Docker 创建镜像 2.1 基于已有的镜像创建

web开发中的长度单位(px,em,ex,rem),如何运用,看完这篇就够了!

原创 2017-03-08 web小二 web前端开发 作为一名前端开发人员,css中的长度单位,都是我们在工作中非常熟悉的名词,因为没有它们,我们就不能声明某个字符应该多大,或者某些图像周围应该留白多少,甚至有时候能导致css不能进行正常工作,所以在很多css属性中,它们都是依赖于长度单位来显示各种页面元素. 1.长度单位包括哪些? 长度单位,其实在我们的生活中,也非常常见,例如,厘米.毫米.英寸,还有经常接触到的像素(px),元素的字体高度(em).字母x的高度(ex).百分比(%)等等这些

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

在上一篇文章:网络爬虫软件哪个好用? 中,我们介绍了目前市面上比较成熟好用的网络爬虫软件, 但是其中有些不能在MAC上使用,因此今天这篇文章我们单独介绍一下在MAC操作系统中有哪些好用的爬虫软件,给大家做一个参考. 还是先说结论吧,赶时间的同志可以看完就闪人了,有两种选择方案: 1.免费不花钱,不需要积分的 注意:这里说的免费功能包括采集数据.导出各种格式的数据到本地,不限制采集和导出的数量,可以下载图片到本地等采集数据所必备的基本功能 你可以选择神箭手云爬虫(www.shenjian.io)和

史上最全自然拼读法,看完这篇就够了

吐血整理史上最全自然拼读法---转需收藏…… 自然拼读教学法又被称为“Phonics”,Phonics已经在欧美国家流行百年,是自然形成的一种发音规则,作为英语母语国家的孩子学习英语读音和拼写的教学法,它主要教授英文字母(letter)与语音(sound)间的对应关系.现在瑞思学科英语小编吐血整理了史上最全自然拼读法的规则及用法,转给有需要的家长宝妈们…… 揭秘自然拼读法 “Phonics自然拼读”对于欧洲国家一点都不陌生,然而,对于中国除了香港.台湾.上海等外交非常发达的城市,仍然是一块有待开

wwwlyjustcom看完这篇,你就会Linux基本操作了,请耐看完199O8836661

只有光头才能变强这个学期开了Linux的课程了,授课的老师也是比较负责任的一位.总的来说也算是比较系统地学习了一下Linux了~本文章主要是总结Linux的基础操作以及一些简单的概念,对于开发者来说,能使用Linux做一些基本的操作是必要的!那么接下来就开始吧,当然了我的Linux仅仅是入门水平,如果有错的地方还需请大家多多包涵,并不吝在评论区指出错误~一.为什么我们要学习Linux相信大部分人的PC端都是用Windows系统的,那我们为什么要学习Linux这个操作系统呢???Windows图形

PDF怎么拆分成多个PDF,看完这篇文章你就明白了

PDF文件对于每一个经常在职场上工作的人来说,是特别常见的一个文档格式,PDF格式深受人们的喜爱,因为是特别好用的,但同时也是比较难进行编辑和修改的,特别是遇到PDF文档过长,为了方便浏览和及时查找对我们有用的内容,这就需要将PDF文档拆分成多个PDF,那么PDF怎么拆分成多个PDF?通过今天的文章就来告诉大家PDF文档拆分的方法,看完这篇文章你就明白了,那么我们就一起来看看吧.?方法一:软件拆分法借助软件:如果想要将PDF文档拆分成多个PDF,那就需要借助迅捷PDF转换器来实现,这个软件有着丰

零基础如何开始学习 Python?看完这篇从小白变大牛!

1.选择Python版本 对于Python工程师来说,Python的版本则是你们的工作环境.所以在学习之前一定要考虑选择一个合适自己的版本,Python3对零基础的小白很友好,易上手.选好版本后就可以开始学习了.创一个小群,供大家学习交流聊天如果有对学python方面有什么疑惑问题的,或者有什么想说的想聊的大家可以一起交流学习一起进步呀.也希望大家对学python能够持之以恒python爱好群,如果你想要学好python最好加入一个组织,这样大家学习的话就比较方便,还能够共同交流和分享资料,给你

如何更准确过滤信息?看完本篇你就知道

无论是使用Excel办公,还是浏览器搜寻关键字,都是需要通过条件过滤来实现.今天,手把手教你实现Java web项目--实现多条件过滤功能. 分页查询需求分析:在列表页面中,显示指定条数的数据,通过翻页按钮完成首页/上一页/下一页/尾页的查询数据分析:通过观察,页面上需要显示下面的几个数据:当前页:currentPage页面大小:pageSize总页数:totalPage首页:1上一页:prevPage下一页:nextPage尾页:endPage总条数:totalCount结果集:result

ae模板怎么套用?看完这篇ae模板套用教程你就懂了

首先我们要知道,模板,是什么?模板就是别人做好了的工程文件,所以东西都已经完成,不需要任何效果方面的修改了.那么ae模板怎么套用?就是你用的时候,替换.修改或者删去某些东西,变成自己的视频.比如片头LOGO模板,你肯定得要有自己的LOGO,去替换模板里的LOGO,然后渲染成片,才会成你的片头:看完这篇ae模板套用教程你就懂了. https://www.macdown.com 本站提供了海量AE模板,我们选择片头LOGO模板,做你自己的片头. 首先下载完后,打开这个模板. 然后看一眼项目栏 我用的