【图(2)】:图的广度优先遍历和深度优先遍历

 

目录

图的遍历

一、图的广度优先遍历(bfs)

二、图的深度优先遍历


图的遍历

给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次。"遍历"即对结点进行某种操作的意思。
在二叉树中,我们对树的最多的操作就是各种遍历,而二叉树的前、中、后序遍历都是深度优先遍历,层序遍历就是广度优先遍历。

而二叉树可以被视为一种特殊类型的图。具体来说,二叉树是一种特殊的有向无环图(Directed Acyclic Graph,DAG)。

在一棵二叉树中,每个节点最多有两个子节点,分别称为左子节点和右子节点。这种结构符合图的定义,其中节点之间通过边(或连接)相互关联。

注意:两个遍历均基于【图(1)】上篇博客的邻接矩阵实现。


一、图的广度优先遍历(bfs)

类似于树,我们从起始顶点开始,同样一层一层遍历:

还是用这个简单图举例: 

假设以B顶点开始广度优先遍历:

 结合邻接矩阵我们可以清晰得出结论:每遍历一层顶点后,下一层需要遍历的顶点为该层顶点能指向的所有顶点。

下面模拟一下过程(与树的层序遍历相同,需要一个队列):

  1. 从B开始,遍历矩阵B对应的这一行,权值不为0的即B指向的顶点(A,C),将它们入队。
  2. A,C入队,对A,C进行相同的操作(poll)。而遍历A这一行发现A又指向了B,但B已经访问过,不能再次访问,因此在遍历前我们需要一个数组来记录每个顶点是否被访问过。再看A指向D,将D入队。
  3. poll出C,遍历C这一行,发现B,D都已经访问过,不需要操作。
  4. poll出D,同上。得到结果:B->A->C->D

综上,只要对二叉树的各种遍历非常熟悉(这里主要是层序遍历),然后刷过一些层序遍历、递归回溯的算法,图的广度优先遍历就非常简单了。

    /*** 图的广度优先遍历** @param v 开始遍历的顶点*/public void bfs(char v) {//1.定义一个数组标记当前顶点是否已经访问过boolean[] visited = new boolean[arrayV.length];//2.申请队列进行bfsQueue<Integer> queue = new ArrayDeque<>();int index = getIndexOfV(v); //记录当前顶点下标,也对应要遍历的行数queue.offer(index);visited[index] = true; //v位置设置为truewhile (!queue.isEmpty()) {index = queue.poll();System.out.print(arrayV[index] + " ");//遍历矩阵的第index行for (int i = 0; i < arrayV.length; i++) {//当前有连通节点且visited为false才能入队if (matrix[index][i] != 0 && !visited[i]) {queue.offer(i);visited[i] = true;}}}}

测试(基于上篇博客的邻接矩阵类):

    public static void main(String[] args) {GraphByMatrix graphByMatrix = new GraphByMatrix(4, false);char[] array = {'A', 'B', 'C', 'D'};graphByMatrix.initArrayV(array);graphByMatrix.addEdge('A', 'B', 1);graphByMatrix.addEdge('A', 'D', 1);graphByMatrix.addEdge('B', 'A', 1);graphByMatrix.addEdge('B', 'C', 1);graphByMatrix.addEdge('C', 'B', 1);graphByMatrix.addEdge('C', 'D', 1);graphByMatrix.addEdge('D', 'A', 1);graphByMatrix.addEdge('D', 'C', 1);//graphByMatrix.printGraph();System.out.println("顶点A的度:" + graphByMatrix.getDevOfV('A'));System.out.print("bfs: ");graphByMatrix.bfs('B');System.out.println();System.out.print("dfs: ");graphByMatrix.dfs('B');}

 

二、图的深度优先遍历(dfs)

图例: 

 还是来看前面那个简单的图:

总结:每次访问该顶点指向的第一个顶点,直到最后一个顶点指向的所有顶点都被访问过,开始回溯。

下面还是模拟一下过程:

  1. 从顶点B开始,遍历B这一行,发现B指向A,递归到A这一层再访问。
  2. 同样遍历A这一行,发现A又指向B了,那我们肯定不能进入这一层(回溯算法中的剪枝操作)。因此再遍历的同时同样需要一个标记数组来记录顶点是否被访问过。再继续遍历A,发现A指向D,D没被访问过,再递归进入D这一层。
  3. 遍历D这一行,D指向A,剪枝;继续遍历,D指向C,C没被访问过,再递归进入C这一层。
  4. 遍历C,发现C所有指向的顶点都已经被访问过。遍历结束后开始回溯。
  5. 回溯过程中,发现所有顶点都已经访问过,即都会被剪掉,因此再不会进入任何的递归操作。直到回到最开始的B这一层,循环结束,遍历完成。顺序:B->A->D->C。
    /*** 图的深度优先遍历** @param v 起始顶点*/public void dfs(char v) {visited = new boolean[arrayV.length];int index = getIndexOfV(v);dfsChild(index);}boolean[] visited; //记录当前顶点是否被访问过private void dfsChild(int index) {System.out.print(arrayV[index] + " ");visited[index] = true;//看矩阵中index这行, 是否还有未访问过的顶点for (int i = 0; i < arrayV.length; i++) {if (matrix[index][i] != 0 && !visited[i]) {dfsChild(i);}}}

测试(基于上篇博客的邻接矩阵类):

    public static void main(String[] args) {GraphByMatrix graphByMatrix = new GraphByMatrix(4, false);char[] array = {'A', 'B', 'C', 'D'};graphByMatrix.initArrayV(array);graphByMatrix.addEdge('A', 'B', 1);graphByMatrix.addEdge('A', 'D', 1);graphByMatrix.addEdge('B', 'A', 1);graphByMatrix.addEdge('B', 'C', 1);graphByMatrix.addEdge('C', 'B', 1);graphByMatrix.addEdge('C', 'D', 1);graphByMatrix.addEdge('D', 'A', 1);graphByMatrix.addEdge('D', 'C', 1);//graphByMatrix.printGraph();System.out.println("顶点A的度:" + graphByMatrix.getDevOfV('A'));System.out.print("bfs: ");graphByMatrix.bfs('B');System.out.println();System.out.print("dfs: ");graphByMatrix.dfs('B');}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++初阶:模板

目录 一.泛型编程 二.函数模板 2.1.函数模板的概念 2.2.函数模板的格式 2.3.函数模板的原理 2.4.函数模板的实例化 隐式实例化 显示实例化 2.5.模板参数的匹配原则 三.类模板 3.1.类模板的格式 3.2.类模板的实例化 3.3.在类模板外部定义成员函数 四.非类型模板参…

【保姆级】Protobuf详解及入门指南

目录 Protobuf概述 什么是Protobuf 为什么要使用Protobuf Protobuf实战 环境配置 创建文件 解析/封装数据 附录 AQin.proto 完整代码 Protobuf概述 什么是Protobuf Protobuf&#xff08;Protocol Buffers&#xff09;协议&#x1f609; Protobuf 是一种由 Google 开…

CrossOver2024实现Mac/Linux上快速运行Win软件和游戏

作为软件产品专家&#xff0c;我对各类软件都有较为深入的了解&#xff0c;下面介绍CrossOver2024这款软件的功能特点。 CrossOver2024是一款功能强大的类虚拟机软件&#xff0c;它的设计目标是在Mac和Linux系统上实现Windows软件和游戏的快速运行。这款软件不仅具有出色的兼容…

Windows下安装Kafka3

本文讲述Windows(win10)下安装Kafka3的方法。基本流程跟《CentOS下安装Kafka3》一样&#xff0c;也是一样需要先安装Java环境&#xff0c;再部署部署Kafka。 首先在官网 Apache Kafka 下载Kafka二进制压缩包。无论是在CentOS还是在Windows下都是下载该压缩包&#xff0c;里面已…

微信小程序实现上下手势滑动切换

效果图 思路 实现一个微信小程序的复合滚动页面&#xff0c;主要通过Swiper组件实现垂直方向的轮播功能&#xff0c;每个轮播项内部使用Scroll-View组件来展示可垂直滚动的长内容&#xff0c;如图片和文本。 代码 <!-- wxml --> <view class"swiper-container…

Vue 中的 key:列表渲染的秘诀

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

vue+elementUI用户修改密码的前端验证

用户登录后修改密码&#xff0c;密码需要一定的验证规则。旧密码后端验证是否正确&#xff1b;前端验证新密码的规范性&#xff0c;新密码规范为&#xff1a;6-16位&#xff0c;至少含数字/字母/特殊字符中的两种&#xff1b;确认密码只需要验证与新密码是否一致&#xff1b; 弹…

Linux进程概念(1)

一、冯诺依曼体系结构 学过计组的同学应该都很熟悉这个结构&#xff0c;可以说这是计算机的基础了&#xff1a; 其实我们日常就经常使用到该结构中的各个部分&#xff1a; 输入单元&#xff1a;包括键盘, 鼠标&#xff0c;扫描仪等。 输出单元&#xff1a;显示器&#xff0c;…

粒子群算法优化RBF神经网络气体浓度预测

目录 完整代码和数据下载链接:粒子群算法优化RBF神经网络气体浓度预测,pso-rbf气体浓度预测(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/abc991835105/88937920 RBF的详细原理 RBF的定义 RBF理论 易错及常见问题 RBF应用实例,粒子群算法优化R…

后勤管理系统|基于SSM 框架+vue+ Mysql+Java+B/S架构技术的后勤管理系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)

目录 文末获取源码 前台首页功能 员工注册、员工登录 个人中心 公寓信息 员工功能模块 员工积分管理 管理员登录 ​编辑管理员功能模块 个人信息 ​编辑员工管理 公寓户型管理 ​编辑公寓信息管理 系统结构设计 数据库设计 luwen参考 概述 源码获取 文末获取源…

Docker基础教程 - 12 常用容器部署-Nginx

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 12 常用容器部署-Nginx 下面介绍一下常用容器的部署。可以先简单了解下&#xff0c;用到再来详细查看。 在 Docker 中部署 Nginx&#xff0c;并通过挂载方式将 Nginx 的配置文件和站点目录挂…

开发指南006-后端配置文件

后端配置文件分为两层&#xff0c;一是部署目录中的内容如下&#xff1a; 这里最重要的是端口号&#xff0c;同一个目录下可以是一个jar包多个配置文件&#xff0c;启动批处理中&#xff0c;按一个配置文件启动一个程序的方式启动多个服务。例如上面目录里的启动批处理文件可以…

Asp .Net Web Forms 系列:配置图片防盗链的几种方法

通过 URL Rewrite Module 组件 URL Rewrite Module 是一个用于在 ASP.NET Web Forms 或其他基于 IIS 的 Web 应用程序中重写 URL 的强大工具。这个模块允许你将复杂的、不易于记忆或不利于搜索引擎优化的 URL 转换为更简洁、更友好的格式。通过 URL 重写&#xff0c;你可以提高…

【存储】ZYNQ+NVMe小型化全国产存储解决方案

文章目录 1、背景2、基础理论3、设计方案3.1、FPGA设计方案3.1.1、NVMe控制器实现3.1.2、NVMe控制器实现 3.2 驱动软件设计方案3.2.1 读写NVMe磁盘软件驱动3.2.2 NVMe磁盘驱动设计3.2.3 标准EXT4文件系统设计 3.3 上位机控制软件设计方案 4、测试结果4.1 硬件测试平台说明4.2 测…

同步通信与异步通信

同步通信&#xff1a;发送方发出数据后&#xff0c;等接收方发回响应以后才发下一个数据包的通讯方式。 异步通信&#xff1a;发送方发出数据后&#xff0c;不等接收方发回响应&#xff0c;接着发送下个数据包的通讯方式。 像IIC 、SPI这类是同步通信(凡是带有时钟信号的基本上…

解码人工智能的幽默:理解其背后的误解与挑战

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

个人职业规划的制定方法

在竞争激烈的职场环境中&#xff0c;一个明确的职业规划对于个人发展至关重要。本文将探讨我的个人职场规划&#xff0c;包括短期和长期目标&#xff0c;以及实现这些目标所需的策略和行动。 一、自我评估 1.1 职业兴趣&#xff1a;我对市场营销和数据分析领域充满热情&#xf…

Day36:安全开发-JavaEE应用第三方组件Log4j日志FastJson序列化JNDI注入

目录 Java-项目管理-工具配置 Java-三方组件-Log4J&JNDI Java-三方组件-FastJson&反射 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用…

day41 动态规划part3

343. 整数拆分 中等 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 但是dp[0] 和 dp[1]为什么是0值得讨论&#xff0c;或者说不用讨论&#xff0c;压根…

加密与安全_PGP、OpenPGP和GPG加密通信协议

文章目录 PGPOpenPGPGPG工作原理工作流程用途案例说明过程 代码实现pom依赖PgpEncryptionUtilPgpDecryptionUtilCommonUtilsPgpEncryptionTest 小结 PGP PGP (Pretty Good Privacy) 是一种加密通信协议&#xff0c;用于保护电子邮件和文件的安全性和隐私。它通过使用加密、数字…