图的遍历:广度优先遍历(BFS)

news/2025/2/11 18:47:01/

1.与树的广度优先遍历之间的联系

先回顾一下树的广度优先遍历也就是层序遍历。

1.树的广度优先遍历(队列)

  1. 若树非空,则根节点入队。
  2. 若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队。
  3. 重复②直到队列为空。

2.图的广度优先遍历

  1. 找到与一个顶点相邻的所有顶点。
  2. 标记哪些顶点被访问过。
  3. 需要一个辅助队列。

注意:这里需要使用要: 图的基本操作中的查找邻接点和查找下一个邻接点的操作。

定义一个标记数组,记录每个顶点是否被访问过。

代码实现:

bool visited[MAX_VERTEX_NUM];//访问标记数组//广度优先遍历
void BFS(Graph G, int v) {//从顶点v出发,广度优先遍历图Gvisit(v);//访问初始顶点vvisited[v] = TRUE;//对v做已访问标记Enqueue(Q, v);//顶点v入队列Qwhile (!isEmpty(Q)) {DeQueue(Q, v);//顶点v出队列for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))//检测v所有邻接点if (!visited[w]) {//w为v的尚未访问的邻接顶点visit(w);//访问顶点wvisited[w] = TRUE;//对w做已访问标记EnQueue(Q, w);//顶点w入队列}//if}// while
}

2.算法分析

值得一提的是:

  • 同一个图的邻接矩阵表示方式唯一,因此广度优先遍历序列唯一。
  • 同一个图邻接表表示方式不唯一,因此广度优先遍历序列不唯一。

如果采用上述算法,若是图是非连通图,则无法遍历完所有结点。
解决方法:遍历完一轮后,重新访问标记数组,找到依旧为false的结点,再调用一次BFS。

修改后代码为:

bool visited[MAX_VERTEX_NUM];//访问标记数组void BFSTraverse(Graph G) {//对图G进行广度优先遍历for (i = 0; i < G.vexnum; ++i)visited[i] = FALSE;//访问标记数组初始化InitQueue(Q);//初始化辅助队列Qfor (i =; i < G.vexnum; ++i)//从0号顶点开始遍历if (!visited[i])//对每个连通分量调用一次BFSBFS(G, i);// vi未访问过,从vi开始BFS
}//广度优先遍历
void BFS(Graph G, int v) {//从顶点v出发,广度优先遍历图Gvisit(v);//访问初始顶点vvisited[v] = TRUE;//对v做已访问标记Enqueue(Q, v);//顶点v入队列Qwhile (!isEmpty(Q)) {DeQueue(Q, v);//顶点v出队列for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))//检测v所有邻接点if (!visited[w]) {//w为v的尚未访问的邻接顶点visit(w);//访问顶点wvisited[w] = TRUE;//对w做已访问标记EnQueue(Q, w);//顶点w入队列}//if}// while
}

结论:对于无向图,调用BFS函数的次数=连通分量数.

3.复杂度分析

1.空间复杂度

最坏情况,辅助队列大小为O(IV|).

2.时间复杂度

  • 邻接矩阵存储的图:访问个顶点需要OI)的时间,查找每个顶点的邻接点都需要O()的时间,而总共有||个顶点时间复杂度= O(IV|2)。
  • 邻接表存储的图:访问个顶点需要O(V)的时间,查找各个顶点的邻接点共需要O(E)的时间,时间复杂度为O(|V|+|E|).

4.广度优先生成树

在广度优先遍历的过程中,将所有结点时经过的路径连上就是一颗生成树。

广度优先生成树由广度优先遍历过程确定。
由于邻接表的表示方式不唯一,因此基于邻接表的广度优先生成树,也不唯一。

对非连通图的广度优先遍历,可得到广度优先生成森林。


http://www.ppmy.cn/news/1074567.html

相关文章

云原生简介 (Cloud Native)

云原生&#xff08;cloud Native&#xff09; 云原生的概念诞生于10年前&#xff0c;netflix 在 AWS 上的一次演讲中。有趣的是当初没有明确的定义&#xff0c;现在也没有明确的定义&#xff0c;对不同的人来说&#xff0c;有不同的概念。 概念 云原生&#xff1a;是在云上构…

stm32之27.iic协议oled显示

屏幕如果无法点亮&#xff0c;需要用GPIO_OType_PP推挽输出&#xff0c;加并上拉电阻 1.显示字符串代码 2.显示图片代码&#xff08;unsigned强制转换&#xff08;char*&#xff09;&#xff09; 汉字显示

Python入门自学进阶-Web框架——40、redis、rabbitmq、git——3

git&#xff0c;一个分布式的版本管理工具。主要用处&#xff1a;版本管理、协作开发。 常见版本管理工具&#xff1a; VSS —— Visual Source Safe CVS —— Concurrent Versions System SVN —— CollabNet Subversion GIT GIT安装&#xff1a;下载安装文件&#xff1a;…

JVM ZGC垃圾收集器

ZGC垃圾收集器 ZGC&#xff08;“Z”并非什么专业名词的缩写&#xff0c;这款收集器的名字就叫作Z Garbage Collector&#xff09;是一款在JDK 11中新加入的具有实验性质[1]的低延迟垃圾收集器&#xff0c;是由Oracle公司研发的。 ZGC收集器是一款基于Region内存布局的&#…

mysql操作

1、字符转Decimal CAST(column AS DECIMAL(9,2)) 2、将计算结果取两位小数&#xff1a; round(column, 2) 3、查询非空 select * from table_XX where id is not null; 4、连表update更新 update a inner join (select yy from b) c on a.id c.id set a.xx c.yy 5、创…

嵌入式软件中如何排查bug?

明确Bug现象&#xff1a;要准确描述Bug出现的场景、现象,能复现就最好。 查看日志信息&#xff1a;嵌入式系统日志可以帮助定位问题,看是否有报错、异常信息。 用仿真工具调试&#xff1a;许多嵌入式芯片都有相应的仿真调试工具,可以在仿真环境下单步跟踪、查看变量值等。 加…

JAVA的ASCII码表

1.完整的ASCII吗表 ASCII值控制字符ASCII值控制字符ASCII值控制字符ASCII值控制字符0NUT32(space)6496、1SOH33&#xff01;65A97a2STX34”66B98b3ETX35#67C99c4EOT36$68D100d5ENQ37%69E101e6ACK38&70F102f7BEL39,71G103g8BS40(72H104h9HT41)73I105i10LF42*74J106j11VT437…

【ES】illegal_argument_exception“,“reason“:“Result window is too large

查询ES数据返回错误&#xff1a; {"root_cause":[{"type":"illegal_argument_exception","reason":"Result window is too large, from size must be less than or equal to: [10000] but was [999999]. See the scroll api for…