图的深度遍历和广度遍历

2023-10-26

理论部分

图的深度遍历和广度遍历都不算很难像极了二叉树的前序遍历和层序遍历,如下面的图,可以用右边的邻接矩阵进行表示,假设以顶点0开始对整幅图进行遍历的话,两种遍历方式的思想如下:

1. 深度优先遍历(depthFirstSearch—DFS)

由初始顶点开始,沿着一条道一直走,当走到走不动的时候,再回来走一条可以走的通的道,然后再继续往下走,直到走不动,再回来…对应于本图来说就是从0开始往前走,到1----->然后从1再往前走,到5----->从5再往前走,到4------->到了这里发现没路可走了------>就往回走,回到5,看5还有没有路,发现没路----->则回到1,看1有没有路,也没有----->再回到0,看0有没有路,发现有------>则由0走到3----->走到这里发现又没有路了----->再往回走,走到0,看0还有没有路,发现有----->则由0走到4,但是4已经被遍历过了,所以再回到0,结束这次遍历过程

但是这时候还有一个2没有遍历啊,该怎么办呢?之前我们是直接就默认从0开始进行往下遍历了,但是从0开始遍历没有一条路可以走到2,为了避免这种情况,我们必须得从每一个顶点开始遍历,这样才能避免漏掉这种只出不进的顶点

于是深度优先遍历得到的遍历结果应为:0 1 5 4 3 2

2.广度优先遍历(broadFirstSearch—BFS)

广度遍历我觉得理解起来更简单,就是一层一层的进行遍历,比如说以0顶点开始,0往下指向1,3,4,遍历的时候就先遍历0,然后再遍历它下一层的1,3,4------>然后分别遍历1,3,4的下一层---->而1,3,4只有1有下一层,则遍历1的下一层5,同理最后遍历2

即广度优先遍历得到的遍历结果应为:0 1 3 4 5 2

和二叉树的层序遍历一样,图的广度遍历也用到了队列,对于下图而言,先将0放入队首----->然后遍历0并将0从队列中取出,同时将0的邻接点1,3,4入队,这样队首就是1----->然后将1出队,并将1的邻接点入队(这里只有5), 这样队首就是3----->然后将3弹出并将3的邻接点入队(这里没有),这样队首就是4----->然后将4弹出并将4的邻接点入队(这里没有),队首就是从1入队的1的第一个邻接点(这里是5)---->然后将5弹出----->直到队列为空这样就完成了由定点0开始的广度优先遍历
在这里插入图片描述

我写的代码如下:

package cn.nrsc.graph;

import java.util.LinkedList;
import java.util.Queue;

//图的遍历
public class Graph {
	// ----------------------------图的表示方式------------------------
	private int vertexSize;// 顶点的数量
	private int[] vertexs;// 顶点对应的数组
	private int[][] matrix;// 邻接矩阵
	private static final int MAX_WEIGHT = 1000;// 代表顶点之间不连通
	private boolean[] isVisited; // 顶点是否已经被访问

	public Graph(int vertexSize) {
		this.vertexSize = vertexSize;
		this.matrix = new int[vertexSize][vertexSize];
		this.vertexs = new int[vertexSize];
		for (int i = 0; i < vertexSize; i++) {
			vertexs[i] = i;
		}

		isVisited = new boolean[vertexSize];
	}
	// ----------------------------图的表示方式------------------------

	// ----------------------------两个重要方法------------------------
	// 获取某个顶点的第一个邻接点
	public int getFirstNeighbor(int index) {
		for (int i = 0; i < vertexSize; i++) {
			if (matrix[index][i] > 0 && matrix[index][i] != 1000) {
				return i;
			}
		}
		return -1; // 如果没有第一个邻接点,则返回-1
	}

	// 获取某个节点V当前邻接点index的下一个邻接点
	public int getNextNeighbor(int v, int index) {
		for (int i = index + 1; i < vertexSize; i++) {
			if (matrix[v][i] > 0 && matrix[v][i] != 1000) {
				return i;
			}
		}
		return -1; // 如果没有返回-1
	}
	// ----------------------------两个重要方法------------------------

	// 图的深度优先遍历算法 ---- 从顶点i进行遍历
	private void depthFirstSearch(int i) {
		// 开始遍历顶点i---所以将其标记为已经遍历了
		isVisited[i] = true;
		// 遍历顶点i的第一个邻接点
		int FN = getFirstNeighbor(i);
		while (FN != -1) {// 如果第一个邻接点存在
			if (!isVisited[FN]) { // 且第一个邻接点没被遍历遍历过
				System.out.println("遍历到了" + FN + "顶点"); // 遍历该顶点
				// 同时递归遍历该顶点的邻接点
				depthFirstSearch(FN);
			}

			// 如果第一个邻接点已经遍历过了---则遍历其第一个邻接点后面的邻接点
			FN = getNextNeighbor(i, FN);
		}

	}

	// 对外提供的深度优先遍历
	public void depthFirstSearch() {
		// 假如图为有向图-----可能遍历到一定程度就再也走不通了
		// 如我例子中的节点2---所以需要对每一个节点进行一下循环
		for (int i = 0; i < vertexSize; i++)
			if (!isVisited[i]) {
				System.out.println("遍历到了" + i + "顶点");
				depthFirstSearch(i);
			}

	}

	// 对外提供的广度优先遍历
	public void broadFirstSearch() {
		// 假如图为有向图-----可能遍历到一定程度就再也走不通了
		// 如我例子中的节点2---所以需要对每一个节点进行一下循环
		for (int i = 0; i < vertexSize; i++)
			if (!isVisited[i]) {
				broadFirstSearch(i);
			}

	}

	private void broadFirstSearch(int i) {
		Queue<Integer> queue = new LinkedList<>();
		// 将遍历到的i压人队列中
		queue.add(i);
		isVisited[i] = true; // 标记该顶点已经被遍历过
		System.out.println("遍历到了" + i + "顶点");
		while (!queue.isEmpty()) {
			// 弹出队首的元素
			Integer head = queue.poll();
			// 获取队首元素第一个邻接点的元素
			int FN = getFirstNeighbor(head);
			while (FN != -1) { // 如果有第一个邻接点
				if (!isVisited[FN]) {// 且该邻接点没有被访问过
					isVisited[FN] = true;// 标记该顶点已经被遍历过
					System.out.println("遍历到了" + FN + "顶点");
					queue.add(FN); // 让FN进人队列
				}
				// 遍历队列首元素head基于FN的下一个元素
				FN = getNextNeighbor(head, FN);
			}
		}

	}

	public static void main(String[] args) {
		Graph graph = new Graph(6);
		int[] v0 = { 0, 4, MAX_WEIGHT, 7, 2, MAX_WEIGHT };
		int[] v1 = { MAX_WEIGHT, 0, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 3 };
		int[] v2 = { MAX_WEIGHT, 9, 0, 5, 6, MAX_WEIGHT };
		int[] v3 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0, MAX_WEIGHT, MAX_WEIGHT };
		int[] v4 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0, MAX_WEIGHT };
		int[] v5 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 1, 0 };

		graph.matrix[0] = v0;
		graph.matrix[1] = v1;
		graph.matrix[2] = v2;
		graph.matrix[3] = v3;
		graph.matrix[4] = v4;
		graph.matrix[5] = v5;
		// 深度优先遍历测试
		// graph.depthFirstSearch(); // 0 1 5 4 3 2

		// 广度优先遍历测试
		graph.broadFirstSearch();// 0 1 3 4 5 2
	}
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图的深度遍历和广度遍历 的相关文章

  • 算法:双指针

    双指针 双指针是一种思想或一种技巧并不是特别具体的算法 具体就是用两个变量动态存储两个结点 来方便我们进行一些操作 通常用在线性的数据结构中 特别是链表类的题目 经常需要用到两个或多个指针配合来记忆链表上的节点 完成某些操作 常见的双指针方
  • 五大常用经典算法

    五大常用算法之一 分治算法 一 基本概念 在计算机科学中 分治法是一种很重要的算法 字面上的解释是 分而治之 就是把一个复杂的问题分成两个或更多的相同或相似的子问题 再把子问题分成更小的子问题 直到最后子问题可以简单的直接求解 原问题的解即
  • 01背包问题变种:从长度为n的数组里选出m个数使和为固定值sum

    这个问题是我从leetcode上一道问题所想到的 原题 如果是从数组中选出2个数相加使之成为固定的数sum 这当然很简单 把数组中的数字遍历一遍 判断另一个数字是否也在数组中即可 代码如下 vector
  • 数据库多维迭代算法

    关键词 数据库 迭代 递归 多维 一 两种传统的数据库迭代结构算法 对于数据库的迭代结构 有两种传统的算法 递归算法和边界算法 比如对于下面图1的结构 图1 递归算法的数据结构如表1所示 节点id 节点值 父节点id 1 1111 2 3
  • 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

    原文 http blog csdn net sup heaven article details 39313731 数据结构中常见的树 BST二叉搜索树 AVL平衡二叉树 RBT红黑树 B 树 B 树 B 树 转载 2014年09月16日
  • BP神经网络与Python实现

    人工神经网络是一种经典的机器学习模型 随着深度学习的发展神经网络模型日益完善 联想大家熟悉的回归问题 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数 并使用该函数进行预测 网络的训练过程即为调节该函数参数提高预测精度的过程
  • 一文弄懂循环链表、双向链表、静态链表

    循环链表 双向链表 静态链表 三遍定律 理解了单链表本文的理解易如反掌 单链表请点击这里 理解了单链表本文的理解易如反掌 单链表请点击这里 理解了单链表本文的理解易如反掌 单链表请点击这里 1 循环链表 将单链表中终端结点的指针端由空指针改
  • 4399 C++笔试题

    1 写出一个函数 取到链表中倒数第二个节点 双链表 node getSec List mylist return mylist m tail gt m prev m prev为链表前指针 单链表 node getSec List mylis
  • 微软2013暑假实习生笔试题

    自己mark一下 以作后备 下面提交原文链接 原文博客 部分题目答案不确定 会持续更新 1 Which of the following calling convention s support s supportvariable leng
  • 循环单链表(C语言版)

    前言 小可爱们 本次一起来看看循环单链表吧 嘻嘻 一 循环单链表的定义 循环单链表是单链表的另一种形式 其结构特点链表中最后一个结点的指针域不再是结束标记 而是指向整个链表的第一个结点 从而使链表形成一个环 和单链表相同 循环链表也有带头结
  • 数据结构之图的两种遍历实现(C语言版)

    上一期文章分享完了图的两种遍历方式 也是两种很重要的算法 DFS和BFS 这两种算法的应用和重要性我就不多说了 内行的人懂的都懂 今天这文章重要就是来上机实现这两种算法 又由于这两种算法都可以由邻接矩阵和邻接表来表示 博主分享的代码都是上机
  • 数据结构与算法书籍推荐

    学习数据结构与算法 还是很有必要看几本相关的书籍 但根据不同基础的人 合适看的书也不一样 因此 针对不同层次 不同语言的人 推荐几本市面上口碑不错的书 1 入门级 针对刚入门的同学 建议不要急着去看那些经典书 像 算法导论 算法 这些比较经
  • 机器学习算法GBDT的面试要点总结-上篇

    1 简介 gbdt全称梯度提升决策树 在传统机器学习算法里面是对真实分布拟合的最好的几种算法之一 在前几年深度学习还没有大行其道之前 gbdt在各种竞赛是大放异彩 原因大概有几个 一是效果确实挺不错 二是即可以用于分类也可以用于回归 三是可
  • 区块链中的哈希算法

    区块链中的密码学 密码学在区块链中的应用主要有两个 哈希算法与非对称加密算法 这次主要对哈希算法进行详细的说明 哈希算法 哈希算法的特点有 1 输入可以为任意大小的字符串 2 产生固定大小的输出 3 可以在合理的时间内算出输出值 若要满足密
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 索引优化之Explain 及慢查询日志

    索引 本质是数据结构 简单理解为 排好序的快速查找数据结构 以索引文件的形式存储在磁盘中 目的 提高数据查询的效率 优化查询性能 就像书的目录一样 优势 提高检索效率 降低IO成本 排好序的表 降低CPU的消耗劣势 索引实际也是一张表 该表
  • 用两个栈实现队列

    目录 一 栈的基本结构及其接口 二 我的队列结构定义 三 我的队列创建及其初始化 四 我的队列入队 五 我的队列出队 六 我的队列取队头元素 七 我的队列判空 八 我的队列销毁 一 栈的基本结构及其接口 栈的结构定义 typedef int
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 【数据结构】双链表的定义和操作

    目录 1 双链表的定义 2 双链表的创建和初始化 3 双链表的插入节点操作 4 双链表的删除节点操作 5 双链表的查找节点操作 6 双链表的更新节点操作 7 完整代码 嗨 我是 Filotimo 很高兴与大家相识 希望我的博客能对你有所帮助
  • 最大流-Dinic算法,原理详解,四大优化,详细代码

    文章目录 零 前言 一 概念回顾 可略过 1 1流网络 1 2流 1 3最大流 1 4残留网络 1 5增广路

随机推荐

  • Linux的时间函数

    2023年7月19日 周三下午 我今天基于GitHub搭建了自己的博客网站 欢迎大家来我的个人博客网站阅读我的博客 巨龙之路的GitHub个人博客 julongzhilu github io 目录 time 函数原型 使用方法 ctime
  • IIC接口介绍

    IIC接口介绍 本章节主要介绍IIC接口工作原理 what 简单介绍 a 术语定义 b 基本概念 why 优点 how 过程 可能出现的问题 a 以下情况 会出现无应答信号 NACK 的情况 本章节主要介绍IIC接口工作原理 what 简单
  • [创业之路-54] :CTO的主要职责与工作内容

    概述 首席技术官 外语词全称chief technology officer 外语词缩略语CTO 是技术资源的行政管理者 其职责是制订有关技术的愿景和战略 把握总体技术方向 监督技术研究与发展 R D 的活动 并对技术选型和具体技术问题进行
  • iava redis工具类

    redis工具类 package com customerNoPlatform configs import java util List import java util Map import java util Objects impo
  • docker的安装和卸载

    docker的卸载 1 先停止docker服务 执行命令 systemctl stop docker 2 删除docker的安装包 先查找docker的安装包 执行命令 yum list installed grep docker 然后删除
  • Vue Quill富文本自定义上传音频/视频

    有时候项目中可能需要在富文本中上传音频 所以 环境 Asp Net Core 文件上传服务 本文不提供 框架很多 Vue 2 0 功能 自定义图片上传 自定义视频上传 自定义音频上传 效果 代码 从若依框架中把Editor index vu
  • 如何查看 gradle 插件的版本号和 gradle 的版本号的对应关系

    地址是 对应关系图
  • 如何实现自适应

    如何实现自适应 利用视口单位实现适配布局 响应式布局的实现依靠媒体查询 Media Queries 来实现 选取主流设备宽度尺寸作为断点针对性写额外的样式进行适配 但这样做会比较麻烦 只能在选取的几个主流设备尺寸下呈现完美适配 即使是通过
  • 英文常见姓氏列表

    写论文时需要统一参考文献格式 外国人的名字经常分不清姓和名 这里汇总了大部分的外国人姓 美国人 1 史密斯 Smith 这一姓氏源自一种职业 是从事金属加工业的男士的姓氏 smith本身有铁匠或锻工之意 金属加工是最初几个对专业能力有特定要
  • 夜莺(Flashcat)V6监控(二):夜莺页面全网最详细功能介绍及案列

    目录 一 如何把数据转发给多个时序库 二 监控仪表盘的配置 三 告警的配置管理 1 告警规则 基础配置 规则配置 分为Metric和Host机器类型的告警 生成配置 通知配置 2 内置规则 3 屏蔽规则 4 订阅规则 5 活跃告警 6 历史
  • Python编程 从入门到实践 12-4

    12 4 按键 创建一个程序 显示一个空屏幕 在事件循环中 每当检测到 pygame KEYDOWN 事件时都打印属性 event key 运行这个程序 并按各种键 看看 Pygame如何响应 import sys import pygam
  • node多版本安装--nvm丝滑切换node版本

    以下是我总结得俩种nvm切换node版本的方式 首先是第一种 需要手动配置的 第一步把自己电脑上面的node卸载 在本机应用程序中卸载 然后手动本机目录删除剩余残留node npm等文件 C Users 86184 AppData C Us
  • 函数的极值点、零点、驻点、拐点的理解

    总结 零点 函数值为0的点 极值点 函数单调性发生变化的点 驻点 函数的一阶导数为0的点 拐点 函数凹凸性变化的点 学习链接 https wenku baidu com view 4a009cf5650e52ea5418982e html
  • [工程数学]1_特征值与特征向量

    首先向b站up DR CAN致敬 视频二刷了 为了收获 理解更多 用极慢的方式 把笔记抄了下来 整理一遍 为了好翻阅 后续会转成pdf格式 放微信公众号后台获取 现代控制理论 2 state space状态空间方程 在state space
  • java是什么_Java是什么?Java有什么用?

    我们经常提到Java 很多小白只听说过但对其并没有太多具体的了解 那么Java是什么 Java有什么用 今天就来探讨一下 我们常常会听说 Java是世界第一语言 很多应用软件的开发都离不开Java Java真的这么强大吗 其实 Java的内
  • 多链路传输技术在火山引擎 RTC 的探索和实践

    动手点关注 干货不迷路 传统的数据传输方式大多是利用一个链路 选择设备的默认网卡进行传输 使用这种方式实现实时音视频通话时 如果默认网络出现问题 如断网 弱网等 用户的通信就会发生中断或者卡顿 影响用户体验 多链路传输 顾名思义 就是使用多
  • electron_vue—实现消息通知 及 解决通知不显示问题

    实现消息通知 window linux macOS 这三个操作系统都为应用程序提供了向用户发送通知的方法
  • python使用pip安装出现pip is configured with locations that require TLS/SSL异常处理方法

    问题描述 最近给服务器安装python环境 通过源码方式安装Python3 8之后 使用pip功能出现异常 提示 root localhost pip3 install you get pip is configured with loca
  • 大数据处理中的关键算子:分割(Split)和选择(Select)

    在大数据处理中 分割 Split 和选择 Select 是两个常用的算子 它们在数据转换和处理过程中发挥着重要的作用 本文将详细介绍这两个算子的功能和使用方法 并附上相应的源代码示例 1 分割 Split 分割算子用于将一个数据集拆分成多个
  • 图的深度遍历和广度遍历

    理论部分 图的深度遍历和广度遍历都不算很难像极了二叉树的前序遍历和层序遍历 如下面的图 可以用右边的邻接矩阵进行表示 假设以顶点0开始对整幅图进行遍历的话 两种遍历方式的思想如下 1 深度优先遍历 depthFirstSearch DFS