广度优先遍历(邻接表,邻接矩阵)

2023-11-12

    广度优先遍历又称为广度优先搜索,简称BFS

    如果说图的深度优先遍历(图的深度优先遍历相关内容:图的深度优先遍历)类似树的前序遍历,那么图的广度优先遍历就类似于树的层序遍历。

    具体遍历过程如下图所示:

    就如上面的第三个图上所编写的序号进行遍历

    我们要实现这样的遍历方法需要一个辅助队列,将处理过后的顶点(比如输出顶点)放入队列中,在找邻接点时找的便是队列顶部的顶点的邻接点,将队列顶部的顶点出队列后获得出队列的顶点的下标,根据下标找到该顶点的所有邻接点,再将所有邻接点依次放到队列中,循环往复直到队列中没有顶点,就遍历完了一个连通图。

    上面图的队列的变化过程:

 当然我们需要一个标志数组,在遍历到顶点后,标记该顶点已被遍历过,避免重复遍历到相同的顶点。

  代码展示:

    ps:该代码包括了队列以及无向网图的创建过程,所以我们需要注意的是邻接矩阵的广度遍历算法:BFSTraverse函数。有关队列的创建以及相关操作可看这里:循环队列,邻接表和邻接矩阵的创建细节可看这里:邻接矩阵邻接表

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
typedef char VertexType;//顶点类型
typedef int EdgeType;//边上的权值类型
#define MAXVEX 20//最大顶点数(开辟储存顶点的一维数组的空间大小)
#define INFINITY 10000//用10000来代表无穷(在储存边的二维数组中,对没有该边存在的表格,权值设为无穷)
//定义图的结构体(图由储存顶点的一维数组和储存边的二维数组,以及记录图中结点数和边数的int类型的变量组成)
struct MGraph
{
	VertexType vexs[MAXVEX];//储存顶点的一维数组
	EdgeType arc[MAXVEX][MAXVEX];//储存边的二维数组
	int Num_vex, Num_arc;//图中的顶点数和边数
};

//定义队列的结构体
struct Queue
{
	//队列储存顶点下标
	//作为队列的数组
	int data[MAXVEX];
	//头指针
	int front;
	//尾指针
	int rear;
};

//初始化队列
void InitQueue(Queue& q)
{
	q.front = 0;
	q.rear = 0;
}

//入队列
void EnQueue(Queue& q, int& index)
{
	//判断队列是否已满
	if ((q.rear + 1) % MAXVEX == q.front)
		return;
	//将数据index放入队列
	q.data[q.rear] = index;
	q.rear = (q.rear + 1) % MAXVEX;
}

//出队列
//将出队列的数据赋给index
void OutQueue(Queue& q, int& index)
{
	index = q.data[q.front];
	q.front = (q.front + 1) % MAXVEX;
}

//判断队列是否为空
bool Juge_Queue(Queue& q)
{
	if (q.front == q.rear)
		//为空返回false
		return false;
	//不为空返回true
	return true;
}

//无向网图的创建
void Create_MGraph(MGraph& G)
{
	int m, n;
	cout << "请输入图的顶点数和边数" << endl;
	cin >> G.Num_vex >> G.Num_arc;
	cout << "请依次输入图的顶点:" << endl;
	for (int i = 0; i < G.Num_vex; i++)
	{
		cin >> G.vexs[i];
	}
	//初始化储存边的二维数组
	for (int i = 0; i < G.Num_vex; i++)
		for (int j = 0; j < G.Num_vex; j++)
		{
			G.arc[i][j] = INFINITY;
		}
	//向二维数组中输入对应边的权值
	for (int k = 0; k < G.Num_arc; k++)
	{
		cout << "请依次输入边(Vm,Vn)的下标m,n" << endl;
		cin >> m >> n;
		cout << "请输入边(" << G.vexs[m-1] << "," << G.vexs[n-1] << ")的权值" << endl;
		cin >> G.arc[m - 1][n - 1];
		//由于是无向网图,所以存在边(m,n),就存在边(n,m)所以我们还应该向二维数组的(n,m)位置输入权值
		G.arc[n - 1][m - 1] = G.arc[m - 1][n - 1];
	}
}


//邻接矩阵的广度遍历算法
void BFSTraverse(MGraph& G)
{

	//标志数组
	//false表示在顶点数组中该下标的顶点没有被遍历过
	bool visited[MAXVEX];
	//初始化标志数组
	for (int i = 0; i < G.Num_vex; i++)
	{
		visited[i] = false;
	}
	//定义队列q
	Queue q;
	//初始化队列
	InitQueue(q);
	//找出一个连通中用于开始遍历的顶点
	//遍历所有结点为了避免图中有不连通的情况,要是图中顶点都是连通的可以不用for循环这一步(但你要先定义一个首次遍历的顶点i)
	for (int i = 0; i < G.Num_vex; i++)
	{
		if (!visited[i])
		{
			//遍历到了标志改为true
			visited[i] = true;
			//输出遍历到的顶点
			cout << G.vexs[i] << " ";
			//将遍历到的顶点的下标放入队列
			//为了一会找该顶点的邻接点
			EnQueue(q, i);
			//找邻接点
			//队列不为空就一直寻找邻接点
			while (Juge_Queue(q))
			{
				int index;
				OutQueue(q, index);
				for (int j = 0; j < G.Num_vex; j++)
				{
					if (G.arc[index][j] != INFINITY && !visited[j])
					{
						visited[j] = true;
						cout << G.vexs[j] << " ";
						EnQueue(q, j);
					}
				}
			}
		}
	}
}
int main()
{
	MGraph G;
	Create_MGraph(G);
	BFSTraverse(G);
	system("pause");
	return 0;
}

    上面程序中所包含的BFSTraverse函数是用于遍历邻接矩阵的,而遍历邻接表也只是因为邻接表与邻接矩阵构造不同而有细微的差异,具体思路没有变化。

    这里我们就只展示遍历的函数

邻接表遍历:

/标志数组
//false表示对应下标的顶点数组中的顶点没有被遍历过
bool visited[MAXSIZE];
//邻接表的广度优先遍历
void BFSTraverse(GraphAdiList& G)
{
	Queue q;
	//初始化队列q
	InitQueue(q);
	//初始化标志数组
	for (int i = 0; i < G.numVertex; i++)
	{
		visited[i] = false;
	}
	//找到第一个用来遍历的顶点
	for (int i = 0; i < G.numVertex; i++)
	{
		if (visited[i] == false)
		{
			visited[i] = true;
			cout << G.Adjext[i].vetex << " ";
			//入队列
			//将下标i入队列
			EnQueue(q, i);
			while (Judge_Queue(q) == true)
			{
				int index;
				//出队列
				OutQueue(q, index);
				//边表结点指针s用来遍历边表
				EdgeNode* s = G.Adjext[index].FirstEdge;
				while (s)
				{
					if (visited[s->adjvex] == false)
					{
						visited[s->adjvex] = true;
						cout << G.Adjext[s->adjvex].vetex << " ";
						EnQueue(q, s->adjvex);
						s = s->next;
					}
				}
			}
		}
	}
}

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

广度优先遍历(邻接表,邻接矩阵) 的相关文章

随机推荐

  • 【程序人生】从土木专员到网易测试工程师,薪资翻3倍,他经历了什么?

    转行对于很多人来说 是一件艰难而又纠结的事情 或许缺乏勇气 或许缺乏魄力 或许内心深处不愿打破平衡 可对于我来说 转行是一件不可不为的事情 因为那意味着新的方向 新的希望 我是学工程管理的 一个工程类的专业 毕业之后的职业轨迹 土木工程专员
  • 【VSCode】1、VSCode 如何连接服务器

    文章目录 一 安装 remote ssh 插件 二 直接连接 三 配置 SSH 公匙 免密登录 一 安装 remote ssh 插件 点击插件搜索框 搜 remote ssh 点击安装 安装完成后就会出现下面的图标 二 直接连接 点击加号
  • r语言中出现unused argument怎么办

    如果在使用 R 语言时出现 unused argument 的错误提示 通常是因为在调用函数时传入了多余的参数 为了解决这个问题 你需要检查你的代码 确保你只传入了函数所需的参数 例如 如果你调用的函数只有两个参数 但你却传入了三个参数 那
  • 蓝桥杯打卡Day7

    文章目录 阶乘的末尾0 整除问题 一 阶乘的末尾0IO链接 本题思路 由于本题需要求阶乘的末尾0 由于我们知道2 5 10可以得到一个0 那么我们就可以找出2的数和5的数 但是由于是阶乘 所以5的数量肯定是小于2的数量 因此我们只需要知道5
  • Python中configparser读取配置

    Python中的configparser模块可以帮助开发者轻松地读取和写入配置文件 配置文件通常用于存储应用程序的设置 例如数据库连接信息 API密钥等等 在本篇博客中 我们将介绍如何使用configparser模块来读取和写入配置文件 读
  • leetcode No1833 雪糕的最大数量

    题目 题解 贪心 排序 贪心 顾名思义就是贪到最多的 本题要求一定数额的钱 要获得最多数量的雪糕 那以我们平常人的思维去买 就是 先买最便宜的 然后再买次便宜的 因此我们可以先将数组排序 排序后从头开始遍历 一直算到前i个雪糕价钱之和大于c
  • 高效素数判断

    素数是指在大于1的自然数中 除了1和它本身以外不再有其他因数的自然数 那么 对于任意数N 判断其是否是素数 就需要从 2 N 一一枚举整除判断 若都不能整除 则N为素数 public static boolean isprime int n
  • 魔改并封装 YoloV5 Version7 的 detect.py 成 API接口以供 python 程序使用

    文章目录 Introduction Section 1 起因 Section 2 魔改的思路 Section 3 代码 Part 1 参数部分 Part 2 识别 API Part 3 完整的 DetectAPI py Part 4 修改
  • 免费商品信息查询接口(条形码)

    最近公司有一个需求 扫描商品条形码显示商品信息 原以为国内应该会免费提供接口 理想总是美好的 现实都是残酷的 在阿里云 京东等API开放平台找了一番 基本都是按次调用收费 公司的需求每位用户一天可能多次调用接口 这样一算 成本太高 既然没有
  • thrift介绍及应用(二)—简单应用

    原文 http blog csdn net guxch article details 12162131 六 一个最简单的实例 Thrift文件 demo thirft 来自官网 如下 plain view plain copy struc
  • 力扣160链表相交(c++版)

    力扣160链表相交 c 力扣题目链接 思路 如果两个链表相交 又都不存在环 那么不难想象这两个链表共同构成了一个Y型 相交部分全部都相同 两链表交点处指针相等 声明指针A指向链表A的头结点 指针B指向链表B的头结点 我们求出两个链表的长度
  • 【基础】创建react脚手架

    React day01 Hello world 一 升级node 1 进入官网 https nodejs org en 2 重新下载最新版本 3 重新安装 一直选择next 既会被覆盖 4 输入 node v 查看最新版本 注 window
  • vue项目中用 cdn 优化

    在我们写项目中 优化问题是不容忽视的 尤其是首屏优化更是重中之重 这里介绍两种方法优化方法 cdn和异步加载 异步请看 http blog csdn net gang456789 article details 78224751 1 cdn
  • Fiddler 八个实用技巧

    目录 前言 1 双击Session时 使响应页始终显示到 json tab页 使请求页始终显示到 webform tab页 2 显示每个Session 的请求IP地址 3 修改响应Header中的Content Type 4 右键sessi
  • 2023AE软件、Adobe After Effects安装下载教程

    2023AE软件是一款由Adobe公司开发的视频编辑软件 也被称为Adobe After Effects 它在广告 电影 电视和网络视频等领域广泛应用 用于制作动态图形 特效 合成和其他视觉效果 该软件支持多种视频和音频文件格式 具有丰富的
  • mybatis增删改查

    MyBatis 是一款优秀的持久层框架 它支持定制化 SQL 存储过程以及高级映射 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息 将接口和
  • C语言第五章第3节用do...while语句实现循环学习导案

    课 题 5 3 用do while语句实现循环 课时安排 2课时 课 型 新授 学 习目标 掌握do while循环语句的一般形式 掌握do while循环语句的执行过程 掌握do while语句和while语句的区别 重点 do whil
  • STM32F4 IAP实现总结

    目录 IAP相关 IAP概念 IAP与ICP ISP的区别 STM32F4的启动模式 FLASH相关 STM32F4 FLASH简介 STM32的内部闪存组织架构和其启动过程 应用IAP时的FLASH分配 IAP工程在Keil中的设置 跳转
  • 通过深度学习实现安全帽佩戴的检测

    北京 上海巡回站 NVIDIA DLI深度学习培训 2018年1月26 1月12日 NVIDIA 深度学习学院 带你快速进入火热的DL领域 阅读全文 gt
  • 广度优先遍历(邻接表,邻接矩阵)

    广度优先遍历又称为广度优先搜索 简称BFS 如果说图的深度优先遍历 图的深度优先遍历相关内容 图的深度优先遍历 类似树的前序遍历 那么图的广度优先遍历就类似于树的层序遍历 具体遍历过程如下图所示 就如上面的第三个图上所编写的序号进行遍历 我