图的深度优先遍历及广度优先遍历
图的引出:前面我们学了线性表和树。线性表局限于一个直接前驱和一个直接后继的关系;树也只能有一个直接前驱也就是父结点。但我们需要表示多对多的关系时,我们就需要用到图这种数据结构。
图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)。
邻接矩阵中,如果两个顶点相连通,则为1,如果不连通,则为零。
图的遍历:
有两种策略。1、深度优先遍历(Depth First Search)。2、广度优先遍历(Broad First Search)。
深度优先遍历思想:深度优先遍历是一种纵向切入的思想。思想是先访问当前顶点,然后再以这个顶点作为初始顶点,访问该顶点的第一个邻接顶点。可以这样理解:每次访问完当前顶点后首先访问当前顶点的第一个邻接顶点。这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。由此可以看出,需要通过递归来实现深度优先遍历。
广度优先遍历思想:广度优先遍历类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的节点的顺序,以便按这个顺序来访问这些结点的邻接结点。
接下来我举一个例子,讲述深度优先遍历的思想
接下来还是以同样一个例子讲述广度优先的遍历思想:
两者的区别:深度优先就是一直到底遍历;而广度优先就好似一张网,一步一步迈进遍历。
这是两者最主要的区别
深度优先遍历的步骤:
- 访问初始结点v,并标记结点v为已访问。
- 查找结点v的第一个邻接结点w。
- 若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。
- 若w未被访问,对w进行深度优先遍历递归(即把w当作另一个v,然后进行步骤123).
- 查找结点v的w邻接结点的下一个邻接结点,转到步骤3.
广度优先遍历的步骤:
- 访问初始结点v并标记结点v为已访问。
- 结点v入队列
- 当队列非空时,继续执行,否则算法结束。
- 出队列,取得队列头结点u。
- 查找结点u的第一个邻接结点w。
- 若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
6.1若结点w尚未被访问,则访问结点w并标记为已访问。
6.2结点w入队列。
6.3查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。
具体实现代码附上,大家可以通过代码仔细去感悟。
package com.liu.chart;import java.util.ArrayList;
import java.util.LinkedList;/*** @author liuweixin* @create 2021-09-20 8:50*/
//图
public class VertexChart {ArrayList<String> VertexList;int[][] edges;//用来储存顶点之间的关系int numOfEdges;//表示边的个数public static void main(String[] args) {
// String[] data = new String[]{"A", "B", "C", "D", "E"};String[] data = new String[]{"1", "2", "3", "4", "5", "6", "7", "8"};VertexChart vertexChart = new VertexChart(data.length);for (String value : data) {vertexChart.addVertex(value);}
// vertexChart.addEdge(0,1,1);
// vertexChart.addEdge(0,2,1);
// vertexChart.addEdge(1,2,1);
// vertexChart.addEdge(1,3,1);
// vertexChart.addEdge(1,4,1);vertexChart.addEdge(0, 1, 1);vertexChart.addEdge(0, 2, 1);vertexChart.addEdge(1, 3, 1);vertexChart.addEdge(1, 4, 1);vertexChart.addEdge(2, 5, 1);vertexChart.addEdge(2, 6, 1);vertexChart.addEdge(3, 7, 1);vertexChart.addEdge(4, 7, 1);vertexChart.addEdge(5, 6, 1);vertexChart.show();System.out.println();vertexChart.dfs();//深度优先遍历:1-2-4-8-5-3-6-7System.out.println();vertexChart.bfs();//广度优先遍历:1-2-3-4-5-6-7-8}public VertexChart(int VertexCount) {edges = new int[VertexCount][VertexCount];VertexList = new ArrayList<String>(VertexCount);numOfEdges = 0;}/*** 对广度优先方法的封装*/public void bfs(){boolean[] isVisited = new boolean[VertexList.size()];//添加该循环的原因在于,有可能数据是分布在两张图甚至多张图上的,所以我们需要对所有的数据实现广度优先遍历//如果数据都分布在单一的一张图上,则不需要加此循环for (int i = 0; i < VertexList.size(); i++) {//对所有数据进行广度优先遍历if(!isVisited[i]){//判断是否访问过bfs(isVisited,i);//进行广度优先遍历}}}/***广度优先* @param isVisited 是否被访问* @param i 初始结点*/public void bfs(boolean[] isVisited, int i){int u;//表示队列的头结点对应的下标int w;//邻接结点w//队列,记录结点访问的顺序LinkedList queue = new LinkedList();//访问结点,输出结点信息System.out.print(VertexList.get(i)+ " ");//标记为已访问isVisited[i]=true;//将结点加入队列queue.addLast(i);while (!queue.isEmpty()){//取出队列的头结点下标u=(Integer)queue.removeFirst();//得到第一个邻接结点的下标ww=getFirstNeighbor(u);while (w!=-1){//找到//是否访问过if(!isVisited[w]){System.out.print(VertexList.get(w)+" ");//标记已经访问isVisited[w]=true;//入队queue.addLast(w);}//以u为前驱点,找w后面的下一个邻接点w=getNextNeighbor(u,w);//体现出广度优先.}}}//对深度优先遍历方法进行封装public void dfs() {boolean[] isVisited = new boolean[VertexList.size()];//添加该循环的原因在于,有可能数据是分布在两张图甚至多张图上的,所以我们需要对所有的数据实现深度优先遍历//如果数据都分布在单一的一张图上,则不需要加此循环for (int i = 0; i < VertexList.size(); i++) {//对所有数据进行深度优先遍历if(!isVisited[i]){//判断是否访问过dfs(isVisited, 0);//进行深度优先}}}/*** 深度优先遍历** @param isVisited 是否被访问* @param i 初始结点*/public void dfs(boolean[] isVisited, int i) {System.out.print(VertexList.get(i) + " ");isVisited[i] = true;//设置该点已被访问过//获取该结点的第一个邻接结点的下标int index = getFirstNeighbor(i);while (index != -1) {//如果循环能进来,此时表明有下一个邻接结点if (!isVisited[index]) {//如果该结点未被访问过//进行递归遍历+回溯dfs(isVisited, index);}//如果该结点已被访问过index = getNextNeighbor(i, index);}}/*** 根据前一个结点的邻接结点的下标获取下一个邻接结点** @param v1* @param v2* @return*/public int getNextNeighbor(int v1, int v2) {for (int i = v2 + 1; i < VertexList.size(); i++) {if (edges[v1][i] > 0) {return i;}}return -1;}/*** 得到该下标的第一个邻接结点** @param index* @return 如果找到,则返回该下标值,如果找不到,返回-1*/public int getFirstNeighbor(int index) {for (int i = 0; i < VertexList.size(); i++) {if (edges[index][i] == 1) {return i;}}return -1;}/*** 显示图的邻接矩阵*/public void show() {for (int[] arr : edges) {for (int data : arr) {System.out.print(data + " ");}System.out.println();}}/*** 获取顶点的个数** @return 返回顶点的个数*/public int getVexCount() {return VertexList.size();}/*** 获取边的个数** @return 返回边的个数*/public int getNumOfEdges() {return numOfEdges;}/*** 返回对应的两个顶点之间的关系** @param v1 第一个顶点的下标* @param v2 第二个顶点的下标* @return 如果返回1,则表示其可以连通;如果返回0,则表示其不连通*/public int getWeight(int v1, int v2) {return edges[v1][v2];}/*** 获取对应下标的顶点值** @param index 对应下标* @return 返回该顶点值*/public String getVertex(int index) {return VertexList.get(index);}/*** 把顶点的数据存储到List中** @param data*/public void addVertex(String data) {VertexList.add(data);}/*** 将顶点之间的关系进行表示** @param v1 表示点的下标,即第几个顶点* @param v2 第二个顶点对应的下边* @param weight 两者的关系。如果为1,则表示两者连通;如果为0,则表示两者不连通。*/public void addEdge(int v1, int v2, int weight) {edges[v1][v2] = weight;edges[v2][v1] = weight;numOfEdges++;}
}
图的深度优先遍历及广度优先遍历相关推荐
- 广度优先搜索生成树怎么画_图的深度优先遍历与广度优先遍历以及最小生成树...
图的深度优先遍历 题目:写出附从每个顶点出发的一次深度优先搜索遍历序列.在纸上画出遍历过程和序列,提交截图. 错误回答 从A点开始遍历:0124-01324-0134-0324-034 从B点开始遍历 ...
- 大话数据结构 17:图的深度优先遍历和广度优先遍历
深度优先遍历 主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底-,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点 ...
- 图:图的邻接表创建、深度优先遍历和广度优先遍历代码实现
邻接表介绍 邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构比较较浪费存储空间.如果不想浪费存储空间,大家肯定会先到链表.需要空间的时候再才想内存去申请,同样适用于图 ...
- 图:图的邻接矩阵创建、深度优先遍历和广度优先遍历详解
邻接矩阵介绍 直接说,邻接矩阵是图的一种存储结构.那么图是什么呢?图是一种逻辑结构,和线性结构.树形结构.集合结构一样 是一种逻辑结构用来描述数据对象中的数据元素之间的关系.来看下图的定义:图(Gra ...
- 数据结构之图:邻接矩阵和邻接表、深度优先遍历和广度优先遍历
简介 线性表是一种线性结构,除了头结点和尾节点,线性表的每个元素都只有一个前取节点和一个后继节点.而树结构则相较于线性表更加复杂,它描述的关系为数据元素之间的父子关系,也是现实世界父子关系的缩影, 一 ...
- 多级树的深度优先遍历与广度优先遍历(Java实现)
目录 多级树的深度优先遍历与广度优先遍历(Java实现) 节点模型 深度优先遍历 广度优先遍历 多级树的深度优先遍历与广度优先遍历(Java实现) 深度优先遍历与广度优先遍历其实是属于图算法的一种,多 ...
- 数据结构—无向图创建邻接矩阵、深度优先遍历和广度优先遍历(C语言版)
无向图创建邻接矩阵.深度优先遍历和广度优先遍历 一.概念解析: (1)无向图: (2)邻接矩阵: 二.创建邻接矩阵: 三.深度遍历.广度遍历 (1)深度遍历概念: (2)广度遍历概念: 四.实例展示 ...
- 实现教材算法7.2利用邻接矩阵构造无向图的算法,在此基础上进行深度优先遍历和广度优先遍历。
软件学院实验报告 姓名: 学号: 专业: 年级: 课程名称 数据结构 实验名称 实验9.图的遍历 实验的准备阶段 实验内 ...
- 二叉树深度优先遍历和广度优先遍历
二叉树深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
二叉树是一种很重要的数据结构,对于二叉树的遍历,有深度优先遍历和广度优先遍历,深度优先遍历又有先序.中序.后续遍历,广度优先遍历就是按层遍历. 1. 深度优先遍历 深度优先遍历,也就是先序.中序.后续 ...
最新文章
- Leetcode 25 K个一组翻转链表 (每日一题 20210719)
- 使用 Arthas 排查 SpringBoot 诡异耗时的 Bug
- Vue3 高级语法(二)—— 自定义指令、Teleport、Vue插件
- python编译备忘
- 单片机c语言数字频率计的课程设计,课程设计基于单片机的简易数字频率计报告.doc...
- ViewBinding使用时出现Could not find method viewBinding() for arguments错误
- 收缩毛孔全过程,很详细! - 健康程序员,至尚生活!
- Yolov5如何在训练意外中断后接续训练
- java如何控制分屏显示,intellij idea 分屏设置 与快捷键
- JQuery事件绑定解绑方法小结
- 联想拯救者wif开不了_联想拯救者为什么连不上wifi
- 解锁高性能计算与区块链应用,阿里云Kubernetes服务召唤神龙
- 22个值得收藏的android开源代码-UI篇,kotlin类型转换
- 动态沙箱是威胁防御的关键所在
- 第二届计算机辅助教育国际大会,【回看】2019年第二届翻译教育国际研讨会 机助译员训练 (CATT): 人机之间...
- 在Linux下使用Vi进阶编辑器Vim编译C/C++
- 波比的w可以挡机器人的q_lol波比W可以挡哪些技能 波比W可以挡石头大招吗
- 青岛旅行规划及玩后感
- 智能硬件一键WIFI配置模式下,对路由设置比较敏感
- 华南理工大学网络教育计算机概论,华南理工大学网络教育学院2018计算机概论作业...