图的遍历(广度优先遍历BFS,深度优先遍历DFS)

目录

图的遍历概念:

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

代码实现如下:

测试如下:

注意:

图的深度优先遍历(DFS):

代码实现如下:

测试如下:

总代码:

结语:


图的遍历概念:

给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次。"遍历"即对结点进行某种操作的意思。由于考试大多考邻接矩阵(GraphByMatrix),故下面的遍历都是用邻接矩阵(GraphByMatrix),不是邻接表(GraphByNode)。

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

广度优先遍历类似于我们前面所学二叉树的层序遍历,一层一层的走,故可以使用队列来模拟实现。

比如:现在有三个抽屉(每个抽屉包含一个红色盒子,红色盒子中又包含一个绿色盒子),所需东西在那个抽屉不清楚,现在要将其找到,广度优先遍历的做法是:

(1)先将三个抽屉打开,在最外层找一遍。

(2)将每个抽屉中红色的盒子打开,再找一遍。

(3)最后将红色盒子中绿色盒子打开,再找一遍。

直到找完所有的盒子,注意:每个盒子只能找一次,不能重复找。

例如下图:

该图的广度优先遍历过程如下:

故其广度优先遍历的结果为:ABCDEFGHI。

代码实现如下:

1、初始化一个布尔类型数组visited,默认所有顶点都没有被遍历到。

2、获取当前开始的顶点V 的下标。

3、定义一个队列,存储当前需要遍历的顶点的下标。

4、取出当前队列的头部。

5、把当前的顶点的这一行都放到队列。

由于getIndexOfV,arrayV,matrix在上一篇文章中已经非常详细的描述过,故这里我只解释其作用,如若需要源码和更加详细的解释请友友前往:图的存储结构 

(1)geiIndexOfV 获取顶点元素在其数组中的下标 。

(2)arrayV 顶点元素的一维数组。

(3)matrix 利用matrix二维数组来存储顶点之间边的权重。

/*** 广度优先遍历* @param v*/public void bfs(char v){//1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到boolean[] visited = new boolean[arrayV.length];//2、获取当前开始的顶点V的下标int index = getIndexOfV(v);//3、定义一个队列,存储当前需要遍历的顶点的下标Queue<Integer> qu = new LinkedList<>();qu.offer(index);//起点放进来while(!qu.isEmpty()){//4、取出当前队列的头部int top = qu.poll();System.out.print(arrayV[top]+":"+"-> ");visited[top] = true;//5、把当前的顶点的这一行都放到队列for(int i = 0;i < arrayV.length;i++){//如果这一行的i下标不等于MAX_VALUE,并且也没有被访问过if(matrix[top][i] != Integer.MAX_VALUE && visited[i] == false){qu.offer(i);//注意,防止重复打印visited[i] = true;}}}System.out.println("null");}

测试如下:

测试代码均围绕下图进行:

遍历结果为BACD显然符合我们的预期。 

注意:

下面话红线的地方不能省去。

如若省去会发生重复遍历例如:

发生了DD的重复打印。

那为什么会发生重复打印呢?这是因为在C出队时,D已经在队列中了但是其还是false,故C出队会再次把D入队,这样就会重复打印。具体过程如下动图:

解决方法:在入队时一起把元素对应下标的visited数组设置为false。

为了方便友友调试下面将测试代码给出:

public static void main(String[] args) {GraphByMatrix graph = new GraphByMatrix(4,true);char[] array = {'A','B','C','D'};graph.initArrayV(array);graph.addEdge('A','B',1);graph.addEdge('A','D',1);graph.addEdge('B','A',1);graph.addEdge('B','C',1);graph.addEdge('C','B',1);graph.addEdge('C','D',1);graph.addEdge('D','A',1);graph.addEdge('D','C',1);graph.bfs('B');}

图的深度优先遍历(DFS):

图的深度优先遍历类似于前面所学二叉树的前序遍历,有路就走,走完没路了再回退,使用递归来实现。

比如:现在有三个抽屉(每个抽屉包含一个红色盒子,红色盒子中又包含一个绿色盒子),所需东西在那个抽屉不清楚,现在要将其找到,深度优先遍历的做法是:

(1)先将第一个抽屉打开,在最外层找一遍。

(2)将第一个抽屉中红色的盒子打开,在红色箱子里找一遍。

(3)将红色盒子中绿色盒子打开,在绿箱子里找一遍。

(4)递归查找剩余两个箱子。

深度优先遍历:将一个抽屉一次性遍历完(包括该抽屉中包含的小盒子),再去递归遍历其它盒子。

其过程如图所示:

其深度优先遍历结果为:ABEGCFDHI。

代码实现如下:

实现一个方法dfschild来进行递归,为什么不用dfs直接递归呢?这是因为如果直接把dfs递归哪visited会一直被开辟,堆上的内存占用太大,要把visited设置在dfs外面才行。

部分流程和前面所说的广度优先遍历类似,关于getIndexOfV,arrayV,matrix在广度优先遍历那已解释故这里不再过多描述。

 /*** 给定顶点,从顶点处开始进行深度优先遍历* @param v*/public void dfs(char v){//1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到boolean[] visited = new boolean[arrayV.length];//2、获取当前开始的顶点V 的下标int index = getIndexOfV(v);//3、开始从index位置进行深度遍历dfsChild(index,visited);System.out.print("null");}/*** 从index位置开始深度优先遍历* @param index* @param visited*/private void dfsChild(int index,boolean[] visited){System.out.print(arrayV[index]+":"+"-> ");visited[index] = true;//当前index位置的,所有的连接点都在这一行for(int i = 0;i < arrayV.length;i++){//如果这一行的i下标不等于0,并且也没有被访问过if(matrix[index][i] != Integer.MAX_VALUE && visited[i] == false){dfsChild(i,visited);}}}

测试如下:

遍历结果为:BADC显然符合我们的预期。

总代码:

import java.sql.SQLOutput;
import java.util.Arrays;
import java.util.Queue;
import java.util.LinkedList;
public class GraphByMatrix {private char[] arrayV;//存放顶点·private int[][] matrix;//存放边private boolean isDirect;//是否是有向图public GraphByMatrix(int size,boolean isDirect){arrayV = new char[size];matrix = new int[size][size];for(int i = 0;i < size;i++){Arrays.fill(matrix[i],Integer.MAX_VALUE);}this.isDirect = isDirect;}/*** 初始化* @param array 顶点集合*/public void initArrayV(char[] array){for(int i = 0;i < array.length;i++){arrayV[i] = array[i];}}/**** @param v1 起始* @param v2 终点* @param weight 权值*/public void addEdge(char v1,char v2,int weight){int index1 = getIndexOfV(v1);int index2 = getIndexOfV(v2);matrix[index1][index2] = weight;if(!isDirect){matrix[index2][index1] = weight;}}/*** 获取顶点元素在其数组中的下标* @param v* @return*/public int getIndexOfV(char v){for(int i = 0;i < arrayV.length;i++){if(v == arrayV[i]){return i;}}return -1;}/*** 获取顶点的度* @param v* @return*/public int getDevOfV(char v){int indexV = getIndexOfV(v);int count = 0;for(int i = 0;i < arrayV.length;i++){if(matrix[indexV][i] != Integer.MAX_VALUE){count++;}}if(isDirect){for(int i = 0;i < arrayV.length;i++){if(matrix[i][indexV] != Integer.MAX_VALUE){count++;}}}return count;}public void printGraph(){for(int i = 0;i < arrayV.length;i++){System.out.print(arrayV[i] + " ");}System.out.println();for(int i = 0;i < matrix.length;i++){for(int j = 0;j < matrix[i].length;j++){if(matrix[i][j] == Integer.MAX_VALUE) {System.out.print("∞ ");}else {System.out.print(matrix[i][j]+" ");}}System.out.println();}}//广度优先遍历/*** 广度优先遍历* @param v*/public void bfs(char v){//1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到boolean[] visited = new boolean[arrayV.length];//2、获取当前开始的顶点V的下标int index = getIndexOfV(v);//3、定义一个队列,存储当前需要遍历的顶点的下标Queue<Integer> qu = new LinkedList<>();qu.offer(index);//起点放进来while(!qu.isEmpty()){//4、取出当前队列的头部int top = qu.poll();System.out.print(arrayV[top]+":"+"-> ");visited[top] = true;//5、把当前的顶点的这一行都放到队列for(int i = 0;i < arrayV.length;i++){//如果这一行的i下标不等于MAX_VALUE,并且也没有被访问过if(matrix[top][i] != Integer.MAX_VALUE && visited[i] == false){qu.offer(i);//注意,防止重复打印
//                    visited[i] = true;}}}System.out.println("null");}//图的深度优先遍历/*** 给定顶点,从顶点处开始进行深度优先遍历* @param v*/public void dfs(char v){//1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到boolean[] visited = new boolean[arrayV.length];//2、获取当前开始的顶点V 的下标int index = getIndexOfV(v);//3、开始从index位置进行深度遍历dfsChild(index,visited);System.out.print("null");}/*** 从index位置开始深度优先遍历* @param index* @param visited*/private void dfsChild(int index,boolean[] visited){System.out.print(arrayV[index]+":"+"-> ");visited[index] = true;//当前index位置的,所有的连接点都在这一行for(int i = 0;i < arrayV.length;i++){//如果这一行的i下标不等于0,并且也没有被访问过if(matrix[index][i] != Integer.MAX_VALUE && visited[i] == false){dfsChild(i,visited);}}}
}

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

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

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

相关文章

Web服务器基础

Web服务器基础 【一】前端概述 【1】HTML HTML&#xff08;超文本标记语言&#xff09;是用于创建网页结构的标记语言。它定义了网页的骨架&#xff0c;包括标题、段落、列表、链接等元素&#xff0c;但没有样式。可以将HTML视为网页的结构和内容的描述。 【2】CSS css&…

阿里云服务器镜像是什么?如何选择镜像?

阿里云服务器镜像怎么选择&#xff1f;云服务器操作系统镜像分为Linux和Windows两大类&#xff0c;Linux可以选择Alibaba Cloud Linux&#xff0c;Windows可以选择Windows Server 2022数据中心版64位中文版&#xff0c;阿里云服务器网aliyunfuwuqi.com来详细说下阿里云服务器操…

Go 是否有三元运算符?Rust 和 Python 是怎么做的?

嗨&#xff0c;大家好&#xff01;本文是系列文章 Go 技巧第十四篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 今天来聊聊在 Go 语言中是否支持三元运算符。这个问题很简单&#xff0c;没有。 首先&#xff0c;什么是三元运算符&#xff1f; 在其他一些编程语言中&a…

MySQL篇之分库分表

一、为什么要分库分表 1.目的 1. 分担了访问压力 2. 解决存储压力 2.分库分表的时机 1. 前提&#xff0c;项目业务数据逐渐增多&#xff0c;或业务发展迅速&#xff0c;单表的数据量达1000W或20G以后。 2. 优化已解决不了性能问题&#xff08;主从读写分离、查询索引…&am…

数据库管理-第152期 Oracle Vector DB AI-04(20240220)

数据库管理152期 2024-02-20 数据库管理-第152期 Oracle Vector DB & AI-04&#xff08;20240220&#xff09;1 常用的向量检索方法聚类图搜索哈希量化 2 Oracle Vector DB中的索引索引&#xff08;默认&#xff09; 索引&#xff08;高级&#xff09;3 EMBEDDINGSSQL EMBE…

阿里云备案服务器买哪种?多少钱?有什么限制条件?

在阿里云备案服务器需要多少钱&#xff1f;目前符合备案条件的阿里云服务器只要30元&#xff0c;并且这台云服务器可以备案5个网站。2核4G配置&#xff0c;价格为30元3个月&#xff0c;也可以选择2核2G轻量服务器&#xff0c;61元一年&#xff0c;阿里云老用户还可以选择99元一…

通俗易懂地理解稀疏性

今天我想与大家探讨的是一个数学和工程学中的重要概念——稀疏性。这个概念可能听起来很抽象&#xff0c;但它实际上贯穿于我们生活中的许多方面。那么&#xff0c;稀疏性到底是什么呢&#xff1f;简单来说&#xff0c;在数学和信号处理领域&#xff0c;一个信号被称为稀疏&…

Eclipse - Text Editors (文本编辑器)

Eclipse - Text Editors [文本编辑器] References Window -> Preferences -> General -> Editors -> Text Editors Displayed tab witdth: 4 勾选 Insert spaces for tabs 勾选 Show line number References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.n…

力扣(LeetCode)数据结构练习题(2)

今天又写了两道关于链表的练习题&#xff0c;来给大家分享一下。巩固一下上一篇学到的链表知识&#xff0c;题目可以然我们更清楚的认识链表。 目录 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 给你单链表的头结点 head &#xff0c;请…

小红书数据分析:sora爆火,为内容行业带来哪些变化

导语 春节还没过完&#xff0c;科技圈就出“大事”了~据悉&#xff0c;OpenAI发布了Sora&#xff0c;一种由文字生成视频的AI工具&#xff0c;且效果极其逼真&#xff0c;打破了多项纪录。Sora的出现&#xff0c;又让人类里通用人工智能AGI近了一步。那么。Sora的出现对于小红…

外贸人做外贸听话要听音

有人说&#xff0c;在做外贸的时候大部分的人都是充当着客服的角色&#xff0c;而且遵循的模式也是一问一答&#xff0c;凡是客户提出的问题&#xff0c;我们都会尽可能详细的回答。 但是对于如何提问客户&#xff0c;却是不知道怎么下手&#xff0c; 于是&#xff0c;在这样的…

hive load data未正确读取到日期

1.源数据CSV文件日期字段值&#xff1a; 2.hive DDL语句&#xff1a; CREATE EXTERNAL TABLE test.textfile_table1(id int COMMENT ????, name string COMMENT ??, gender string COMMENT ??, birthday date COMMENT ????,.......) ROW FORMAT SERDE org.apache.…

wordpress企业网站模板免费

绿色风格的wordpress免费模板&#xff0c;经测试可以免费下载的WP模板。 https://www.wpniu.com/themes/300.html 简洁大气的文化艺术类wordpress模板&#xff0c;可以免费下载&#xff0c;实用易上手&#xff0c;新手也适合。 https://www.wpniu.com/themes/304.html 高端大…

C++面试宝典第30题:分发饼干

题目 假设你是一位非常棒的家长,想要给你的孩子们分发一些小饼干。但是,每个孩子最多只能给一块饼干。对每一个孩子i,都有一个胃口值gi,这是能让孩子们满足胃口的饼干的最小尺寸。对每一块饼干j,都有一个尺寸sj。如果sj >= gi,我们就可以将这个饼干j分配给孩子i,这个…

golangci-lint如何关闭typecheck

https://github.com/golangci/golangci-lint/issues/2912 typecheck是go源码的校验&#xff0c;无法通过.golangci.yml配置关闭 可以直接在golangci-lint源码层面关闭typecheck

Springboot AOP开发

Springboot AOP开发 一 AOP概述 AOP&#xff0c;即面向切面编程&#xff0c;简言之&#xff0c;面向方法编程。 针对方法&#xff0c;在方法的执行前或执行后使用&#xff0c;用于增强方法&#xff0c;或拓展。 二 AOP开发 1.引入 spring-boot-starter-aop 在SpringBoot项…

【高效开发工具系列】PyCharm使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

自养号测评低成本高效率推广,安全可控

测评的作用在于让用户更真实、清晰、快捷地了解产品以及产品的使用方法和体验。通过买家对产品的测评&#xff0c;也可以帮助厂商和卖家优化产品缺陷&#xff0c;提高用户的使用体验。这进而帮助他们获得更好的销量&#xff0c;并更深入地了解市场需求。因此&#xff0c;测评在…

.NET高级面试指南专题九【 泛型概念,常用泛型类和方法,泛型约束,协变与逆变】

C#中的泛型&#xff08;Generics&#xff09;是一种强大的编程特性&#xff0c;它允许你在编写代码时使用不特定数据类型&#xff0c;而在编译时确定这些数据类型。泛型使得代码更加灵活、可重用&#xff0c;并提高了类型安全性。 功能和原理 泛型允许你编写能够与不同数据类型…

数字孪生核心技术揭秘(五):BIM究竟是解药还是毒药?

一、关于BIM的那些幻想 1.1 BIM是“数字孪生城市”最后一块拼图&#xff1f; 近几年&#xff0c;CIM概念越来越流行&#xff0c;已经成为数字孪生城市的主流数据模型。CIM原始概念指的是“城市信息模型”&#xff1b;2015年同济大学吴志强院士基于CIM概念提出“城市智慧模型”&…