图的深度遍历(DFS)和广度遍历(BFS)详解

2023-11-04

目录

 

1 前奏(邻接表)

2 深度遍历

3 广度遍历


1 前奏(邻接表)

图作为种比较繁琐的数据结构,在进行图的操作之前,首先应该用合适的数据类型来存储图的信息。

我们使用邻接表来存储,它是一种链式的存储结构。所谓邻接表就是对途中的每个顶点建立一个单链表。看一下下面的定义就明白了。

邻接表的定义如下:

//边
typedef struct ArcNode
{
	int adjvex;//该边所指向的节点的位置
	struct ArcNode* nextarc;//指向下一条边的指针
	int info;//存储边的相关信息,比如权重
}ArcNode;
//顶点
typedef struct VNode
{
	char data;//顶点信息
	ArcNode* firstarc;//指向第一条边的指针
}VNode;
//邻接表的定义
typedef struct AGraph
{
	VNode adjlist[MAXSIZE];//邻接表,里面存储着图种的所有顶点
	int n;//顶点的个数
	int e;//边的个数
}AGraph;

2 深度遍历

图的深度优先搜索遍历(DFS)类似于二叉树的先序遍历。它的基本思想是,从访问节点v出发,并将其标为已访问过,然后选取与v邻接的未被访问过的任何一个顶点w,并访问它,再选取与w邻接的未被访问的任一顶点并访问,以重复进行。当一个顶点所有的邻接顶点都被访问过时,则依次退回到最近被访问过的顶点,若该顶点还有其他邻接顶点未被访问,则从这些未被访问的顶点中取一个顶点并重复上述访问过程,直至所有的顶点都被访问过为止。

 

我们假设从顶点A出发开始访问,那么可能的访问序列有:

  • A,D,C,E,B
  • A,D,E,C,V
  • A,C,D,B,E

不限于以上三种,这与图的邻接表有关。

接下来是代码的实现:

首先我们看一个连通图的深度优先搜索遍历:

int vist[MAXSIZE];//用于记录访问过的节点,0代表未访问,1代表已访问
//G为邻接表,v为起始节点
void DFS(AGraph* G, int v)
{
	ArcNode* p;
	vist[v] = 1;
	cout << v << endl;
	p = G->adjlist[v].firstarc;//p指向v节点的第一条边。
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)
			DFS(G, p->adjvex);//递归的进行访问
		p = p->nextarc;//指向下一条边
	}
}

上述的代码只适合连通图,如果一个图中有孤立的节点,即当这个图不是连通图的时,就应该从所有的节点开始进行遍历,如下:

void dfs(AGraph* g)
{
	for (int i = 0; i < g->n; ++i)
            if(visit[i]==0)
		DFS(g, i);
}

3 广度遍历

图的广度优先搜索遍历类似于树的层次遍历。它的基本思想是:首先访问起始顶点v,然后选取与v邻接的全部顶点进行访问,再依次访问邻接顶点的邻接顶点,以此类推,直至所有的顶点都被访问。

上述图从A出发,我们假设D,C,B分别是A指向的第一个、第二个和第三个节点,那么广度遍历的序列为:

A,D,C,B,E

连通图的广度遍历的代码如下所示:

void BFS(AGraph* G, int v, int visti[MAXSIZE])
{
	ArcNode* p;
	queue<int> que;
	cout << v << endl;
	visit[v] = 1;
	que.push(v);
	while (!que.empty())
	{
		int j = que.top();//得到队头元素
		que.pop();//出队
		p = G->adjlist[j].firstaec;
		while (p != NULL)
		{
			if (visit[] p->adjvex == 0)
			{
				cout << p->adjvex << endl;
				visit[p->adjvex] = 1;
				que.push(p->adjvex);
			}
			p = p->nextarc;//指向下一条边
		}
		
	}
}

上述代码是针对连通图的,那么对于非连通图,需要从不同的节点开始进行访问,充分考虑到孤立节点:

void bfs(AGraph* g)
{
	for (int i = 0; i < g->n; ++i)
            if(visit[i]==0)
		BFS(g, i);
}

 

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

图的深度遍历(DFS)和广度遍历(BFS)详解 的相关文章

随机推荐

  • uniapp蓝牙连接操作详解

    初始化蓝牙 openBluetoothAdapter uni openBluetoothAdapter 打开蓝牙适配器接口 success res gt 已打开 fail err gt 未打开 uni showToast icon none
  • linux的mysql如何删除用户_linux mysql增加用户,删除用户,以及用户权限

    一些基本的命令 登录 mysql u username p 显示所有的数据库 show databases 使用某一个数据库 use databasename 显示一个数据库的所有表 show tables 退出 quit 删除数据库和数据
  • 为什么kafka 需要 subscribe 的 group.id?我们是否需要使用 commitSync 手动提交偏移量?

    目录 一 为什么需要带有 subscribe 的 group id 二 我们需要使用commitSync手动提交偏移量吗 三 如果我想手动提交偏移量 该怎么做 一 为什么需要带有 subscribe 的 group id 消费概念 Kafk
  • 获取当前系统的时间

    1 time函数 函数原型 time t time time t t 函数功能 获取当前系统的时间 函数的返回值和参数都是time t类型的变量 且都可以获取当前系统的时间 使用前先定义一个time t类型的变量 例 time t t ti
  • 优秀logo设计解析_产品设计中十种常见LOGO工艺处理手法解析

    在制造业当中 一个产品中logo的如何应用 更能够体现这个品牌的形象 所谓细节决定成败 logo的处理更是产品设计细节中的细节 而产品设计师在完成产品设计时会考虑到logo的位置 样式以及工艺处理 作为一个优秀设计师那肯定需要了解LOGO的
  • Java中Lock锁的基本使用

    1 创建锁 2 加锁 3 解锁 package com liu demo01 import java util concurrent locks Lock import java util concurrent locks Reentran
  • Qt开发 之 抓取崩溃信息(读这一篇就够了)

    文章目录 1 简介 1 1 常见崩溃 1 2 BreakPad 1 2 1 源码 1 2 2 原理 1 3 用BreakPad处理崩溃具体流程 2 Qt中加入BreakPad 2 1 在项目中引入BreakPad模块 2 2 google
  • 入门级题解:2000. 反转单词前缀

    题目 给你一个下标从 0 开始的字符串 word 和一个字符 ch 找出 ch 第一次出现的下标 i 反转 word 中从下标 0 开始 直到下标 i 结束 含下标 i 的那段字符 如果 word 中不存在字符 ch 则无需进行任何操作 思
  • 软件测试职业生涯需要编写的全套文档模板,收藏这一篇就够了 ~

    作为一名测试工程师 在整个的职业生涯中 会涉及到各种不同类型的文档编写 大体包括如下 对应文档模板及文档编写视频如下 一 测试岗位必备的文档 在一个常规的软件测试流程中 会涉及到测试计划 测试方案 测试用例 测试报告的编写 这些文档也是软件
  • el-select绑定值赋值后,页面无法显示对应label值

    el select绑定值赋值后 页面无法显示对应label值 this lunwen achmId 1 页面也显示1 无法显示1对应的label值 这种情况大多数是数据类型不统一 比如页面绑定为number类型 而赋值为string类型 或
  • 多模态深度学习综述总结 与 目标检测多模态融合领域论文推荐

    文章目录 一 多模态学习定义及应用 二 模态表示 2 1 单模态表示 2 1 1 语句模态表示 2 1 2 视觉模态表示 2 1 3 声音模态表示 略 2 2 多模态表示 2 2 1 模态共作用语义表示 联合表示 2 2 2 模态约束语义表
  • 无公网IP,在外公网远程访问RabbitMQ服务「内网穿透」

    文章目录 前言 1 安装erlang 语言 2 安装rabbitMQ 3 内网穿透 3 1 安装cpolar内网穿透 支持一键自动安装脚本 3 2 创建HTTP隧道 4 公网远程连接 5 固定公网TCP地址 5 1 保留一个固定的公网TCP
  • Leedcode编程题283:移动零----C++实现

    目的 旨在记录在Leedcode网上刷题的过程 记录心得 题目 给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 示例 输入 0 1 0 3 12 输出 1 3 12 0 0 说明 必须在原数组上
  • SpringBoot连接超时导致的502错误案例

    1 问题描述 内部系统之间通过Nginx来实现路由转发 但最近发现有一个系统 经常报502错误 每天达到上百次 完全无法忍受 2 原因排查 于是进行排查 发现配置人员把连接超时时间 server tomcat connection time
  • 006 从不同的角度理解数组名的意义——“C”

    一 数组名的意义是什么 引入 1 数组名的意义 sizeof 数组名 这里的数组名表示整个数组 计算的是整个数组的大小 数组名 这里的数组名表示整个数组 取出的是整个数组的地址 除此之外所有的数组名都表示首元素的地址 2 strlen函数基
  • js 修改服务器控件,js设置服务器控件的值

    js设置服务器控件的值 内容精选 换一换 规划数据服务器与集群处于同一内网 数据服务器IP为192 168 0 90和192 168 0 91 数据源文件格式为CSV 创建导入的目标表tpcds reasons CREATE TABLE t
  • 驱动开发概念详解

    1 什么是驱动 能够驱使硬件实现特定功能的软件代码 可以根据驱动程序是否依赖于系统内核将其分为裸机驱动和系统驱动 1 1裸机驱动 编写的驱动代码中没有进行任何内核相关的API调用 开发者查询资料配置寄存器完成硬件相关控制 不依赖于系统内核
  • 企业治理实战-经验分享

    该文章已同步到语雀公开知识库 大数据技术架构手册 1 中 公众号后台回复 小程序注册码 可免费查看面试题小程序 前言 作为一名数据人 常常自嘲为SQL Boy 某天突然发现原来SQL boy还有一些更高级的工作内容 数据治理 这两年也有很多
  • 第41篇-小某书timestamp2参数分析【2022-08-15】

    提前声明 该专栏涉及的所有案例均为学习使用 如有侵权 请联系本人删帖 文章目录 一 前言 二 加密分析 三 改版 一 前言 今天我们来分析一下timestamp2参数 aHR0cHM6Ly93d3cueGlhb2hvbmdzaHUuY29t
  • 图的深度遍历(DFS)和广度遍历(BFS)详解

    目录 1 前奏 邻接表 2 深度遍历 3 广度遍历 1 前奏 邻接表 图作为种比较繁琐的数据结构 在进行图的操作之前 首先应该用合适的数据类型来存储图的信息 我们使用邻接表来存储 它是一种链式的存储结构 所谓邻接表就是对途中的每个顶点建立一