数据结构 | 图的深度优先遍历和广度优先遍历(C语言)

news2024/12/26 23:03:11

一、数据结构定义

1、图

#define MaxVertexNum 100 // 最大可存储的节点数目

/*图*/
typedef char VexterType;
typedef int EdgeType;

typedef struct GraphMatrix {
	VexterType Vexs[MaxVertexNum];				//结点 
	EdgeType Edges[MaxVertexNum][MaxVertexNum];	//边
	int vexnum, arcnum;							//当前点数和边数
}*MGraph;

int visited[MaxVertexNum]; // 记录是否访问该节点,访问过为1,否则为0

使用邻接矩阵法存储图的信息,其中

  • 一维矩阵 Vexs[] 存储节点信息
  • 二维矩阵 Edges[][] 存储边的信息
  • 一维矩阵 visited[] 记录当前节点是否被访问过,用于后面的遍历

本文所使用的图的结构如下:

对应的 Vexs[] 为:A,B,C,D,E,F(对应的数组下标从0到5)

对应的 Edges[][] 如下:

 2、队列

/*队列*/
typedef int QueueType;
typedef struct QueueNode {
	QueueType data;
	struct QueueNode* next;
}QueueNode;

typedef struct {
	QueueNode* front, * rear;
}LinkQueue;

图的广度优先遍历BFS需要使用队列进行辅助

二、方法概览

1、队列

void initQueue(LinkQueue* Q);//初始化队列
int isQueueEmpty(LinkQueue* Q);//判断队列是否为空
void enQueue(LinkQueue* Q, QueueType data);//入队
int deQueue(LinkQueue* Q, QueueType* data);//出队

2、图

void printGraph(MGraph G);//打印图的邻接矩阵
MGraph initGraph();//初始化图并输入数据
int adjacent(MGraph G, int x, int y);//判断是否存在某条边(x,y)
int firstNeighbor(MGraph G, int v);//求点v的第一个邻接点
int nextNeighbor(MGraph G, int v, int w);//求点v的邻接点w的下一个邻接点

void visit(MGraph G, int v);//访问该节点的信息
void BFS(MGraph G, LinkQueue Q, int v);// 广度优先遍历
void BFSTraverse(MGraph G);//广度优先遍历 主函数
void DFS(MGraph G, int v);//深度优先遍历
void DFSTraverse(MGraph G);//深度优先遍历 主函数

三、方法详解

1、队列

//初始化队列
void initQueue(LinkQueue* Q) {
	Q->front = Q->rear = (QueueNode*)malloc(sizeof(QueueNode)); // 分配头节点
	Q->front->next = NULL; //初始化为空
}
//判断队列是否为空
int isQueueEmpty(LinkQueue* Q) {
	if (Q->front == Q->rear) return 1;
	else return 0;
}
//入队
void enQueue(LinkQueue* Q, QueueType data) {
	QueueNode* news = (QueueNode*)malloc(sizeof(QueueNode));
	news->data = data; // 创建新节点,插入队列尾部 
	news->next = NULL;
	Q->rear->next = news;
	Q->rear = news;
}
//出队
int deQueue(LinkQueue* Q, QueueType* data) {
	if (Q->front == Q->rear) return 0;
	QueueNode* del = Q->front->next;
	*data = del->data;
	Q->front->next = del->next;
	if (Q->rear == del)
		Q->rear = Q->front; // 若原队列只有一个节点,删除后变空 
	free(del);
	return 1;
}

2、图

(1)基本操作

// 打印图的邻接矩阵
void printGraph(MGraph G) {
	int i, j;
	printf("G->Edges[][] = \n\t");

	for (i = 0; i < G->vexnum; ++i)
		printf(" %c \t", G->Vexs[i]);
	printf("\n");

	for (i = 0; i < G->vexnum; ++i) {
		printf(" %c \t", G->Vexs[i]);
		for (j = 0; j < G->vexnum; j++)
			printf(" %d \t", G->Edges[i][j]);
		printf("\n");
	}
}

// 初始化图并输入数据
MGraph initGraph() {
	int i, j;
	MGraph G = (MGraph)malloc(sizeof(struct GraphMatrix));
	G->vexnum = 6;
	G->arcnum = 14;

	/* 初始化图的邻接矩阵 Edges[MaxVertexNum][MaxVertexNum] */
	for (i = 0; i < G->vexnum; i++) {
		for (j = 0; j < G->vexnum; j++) {
			G->Edges[i][j] = 0;	 
		}
	}

	/* 输入图的结点矩阵 Vexs[MaxVertexNum] */
	int v[6] = { 'A','B','C','D','E','F' };
	for (i = 0; i < G->vexnum; i++)
		G->Vexs[i] = v[i];

	/* 输入图的边权 */
	int  start_vex[14] = { 0,0,0,1,1,1,2,2,3,3,4,4,5,5 };
	int    end_vex[14] = { 1,2,3,0,4,5,0,1,0,5,1,2,1,3 };
	for (i = 0; i < G->arcnum; i++)
		G->Edges[start_vex[i]][end_vex[i]] = 1;
	return G;
}

// 判断是否存在某条边(x,y)
int adjacent(MGraph G, int x, int y) {
	if (G->Edges[x][y] == 1)
		return 1;
	else
		return -1;
}

// 求点v的第一个邻接点
// 若有返回顶点号,否则返回-1
int firstNeighbor(MGraph G, int v) {
	for (int i = 0; i < G->Vexs; i++) {
		if (G->Edges[v][i] == 1)
			return i;
	}
	return -1;
}

// 求点v的邻接点w的下一个邻接点
// 若有返回顶点号,否则返回-1
int nextNeighbor(MGraph G, int v, int w) {
	if (w < G->vexnum) {
		for (int i = w + 1; i < G->vexnum; i++) {
			if (G->Edges[v][i] == 1)
				return i;
		}
		return -1;
	}
	return -1;
}

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

// 访问该节点的信息
void visit(MGraph G,int v) {
	printf("%c ",G->Vexs[v]);
}

// 深度优先遍历
void DFS(MGraph G, int v) {
	visit(G, v);
	visited[v] = 1;
	for (int w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w)) {
		if (visited[w] == 0)
			DFS(G, w);
	}
}

// 深度优先遍历 主函数
void DFSTraverse(MGraph G) {
	for (int i = 0; i < G->vexnum; ++i) {
		visited[i] = 0;
	}
	for (int i = 0; i < G->vexnum; ++i) {
		if (visited[i] == 0)
			DFS(G, i);
	}
}

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

// 访问该节点的信息
void visit(MGraph G,int v) {
	printf("%c ",G->Vexs[v]);
}

// 广度优先遍历
void BFS(MGraph G, LinkQueue Q, int v) {
	visit(G, v);
	visited[v] = 1;
	enQueue(&Q, v);
	while (!isQueueEmpty(&Q)) {
		deQueue(&Q, &v);
		for (int w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w)) {
			if (visited[w] == 0) {
				visit(G, w);
				visited[w] = 1;
				enQueue(&Q, w);
			}
		}
	}
}

// 广度优先遍历 主函数
void BFSTraverse(MGraph G) {
	for (int i = 0; i < G->vexnum; ++i) {
		visited[i] = 0;
	}
	LinkQueue Q;
	initQueue(&Q);
	for (int i = 0; i < G->vexnum; ++i) {
		if (visited[i] == 0)
			BFS(G, Q, i);
	}
}

四、运行结果

        main方法代码如下:

int main() {
	MGraph G = initGraph();
	printGraph(G);

	printf("\n广度优先遍历 : ");
	BFSTraverse(G);

	printf("\n深度优先遍历 : ");
	DFSTraverse(G);
	return 0;
}

        运行结果如下:

 五、源代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define MaxVertexNum 100 // 最大可存储的节点数目

/*图*/
typedef char VexterType;
typedef int EdgeType;

typedef struct GraphMatrix {
	VexterType Vexs[MaxVertexNum];				//结点 
	EdgeType Edges[MaxVertexNum][MaxVertexNum];	//边
	int vexnum, arcnum;							//当前点数和边数
}*MGraph;

int visited[MaxVertexNum]; // 记录是否访问该节点,访问过为1,否则为0


/*队列*/
typedef int QueueType;
typedef struct QueueNode {
	QueueType data;
	struct QueueNode* next;
}QueueNode;

typedef struct {
	QueueNode* front, * rear;
}LinkQueue;

void initQueue(LinkQueue* Q);//初始化队列
int isQueueEmpty(LinkQueue* Q);//判断队列是否为空
void enQueue(LinkQueue* Q, QueueType data);//入队
int deQueue(LinkQueue* Q, QueueType* data);//出队


void printGraph(MGraph G);//打印图的邻接矩阵
MGraph initGraph();//初始化图并输入数据
int adjacent(MGraph G, int x, int y);//判断是否存在某条边(x,y)
int firstNeighbor(MGraph G, int v);//求点v的第一个邻接点
int nextNeighbor(MGraph G, int v, int w);//求点v的邻接点w的下一个邻接点

void visit(MGraph G, int v);//访问该节点的信息
void BFS(MGraph G, LinkQueue Q, int v);// 广度优先遍历
void BFSTraverse(MGraph G);//广度优先遍历 主函数
void DFS(MGraph G, int v);//深度优先遍历
void DFSTraverse(MGraph G);//深度优先遍历 主函数



//初始化队列
void initQueue(LinkQueue* Q) {
	Q->front = Q->rear = (QueueNode*)malloc(sizeof(QueueNode)); // 分配头节点
	Q->front->next = NULL; //初始化为空
}
//判断队列是否为空
int isQueueEmpty(LinkQueue* Q) {
	if (Q->front == Q->rear) return 1;
	else return 0;
}
//入队
void enQueue(LinkQueue* Q, QueueType data) {
	QueueNode* news = (QueueNode*)malloc(sizeof(QueueNode));
	news->data = data; // 创建新节点,插入队列尾部 
	news->next = NULL;
	Q->rear->next = news;
	Q->rear = news;
}
//出队
int deQueue(LinkQueue* Q, QueueType* data) {
	if (Q->front == Q->rear) return 0;
	QueueNode* del = Q->front->next;
	*data = del->data;
	Q->front->next = del->next;
	if (Q->rear == del)
		Q->rear = Q->front; // 若原队列只有一个节点,删除后变空 
	free(del);
	return 1;
}


// 打印图的邻接矩阵
void printGraph(MGraph G) {
	int i, j;
	printf("G->Edges[][] = \n\t");

	for (i = 0; i < G->vexnum; ++i)
		printf(" %c \t", G->Vexs[i]);
	printf("\n");

	for (i = 0; i < G->vexnum; ++i) {
		printf(" %c \t", G->Vexs[i]);
		for (j = 0; j < G->vexnum; j++)
			printf(" %d \t", G->Edges[i][j]);
		printf("\n");
	}
}
// 初始化图并输入数据
MGraph initGraph() {
	int i, j;
	MGraph G = (MGraph)malloc(sizeof(struct GraphMatrix));
	G->vexnum = 6;
	G->arcnum = 14;

	/* 初始化图的邻接矩阵 Edges[MaxVertexNum][MaxVertexNum] */
	for (i = 0; i < G->vexnum; i++) {
		for (j = 0; j < G->vexnum; j++) {
			G->Edges[i][j] = 0;
		}
	}

	/* 输入图的结点矩阵 Vexs[MaxVertexNum] */
	int v[6] = { 'A','B','C','D','E','F' };
	for (i = 0; i < G->vexnum; i++)
		G->Vexs[i] = v[i];

	/* 输入图的边权 */
	int  start_vex[14] = { 0,0,0,1,1,1,2,2,3,3,4,4,5,5 };
	int    end_vex[14] = { 1,2,3,0,4,5,0,1,0,5,1,2,1,3 };
	for (i = 0; i < G->arcnum; i++)
		G->Edges[start_vex[i]][end_vex[i]] = 1;
	return G;
}
// 判断是否存在某条边(x,y)
int adjacent(MGraph G, int x, int y) {
	if (G->Edges[x][y] == 1)
		return 1;
	else
		return -1;
}
// 求点v的第一个邻接点
// 若有返回顶点号,否则返回-1
int firstNeighbor(MGraph G, int v) {
	for (int i = 0; i < G->vexnum; i++) {
		if (G->Edges[v][i] == 1)
			return i;
	}
	return -1;
}
// 求点v的邻接点w的下一个邻接点
// 若有返回顶点号,否则返回-1
int nextNeighbor(MGraph G, int v, int w) {
	if (w < G->vexnum) {
		for (int i = w + 1; i < G->vexnum; i++) {
			if (G->Edges[v][i] == 1)
				return i;
		}
		return -1;
	}
	return -1;
}
// 访问该节点的信息
void visit(MGraph G,int v) {
	printf("%c ",G->Vexs[v]);
}
// 广度优先遍历
void BFS(MGraph G, LinkQueue Q, int v) {
	visit(G, v);
	visited[v] = 1;
	enQueue(&Q, v);
	while (!isQueueEmpty(&Q)) {
		deQueue(&Q, &v);
		for (int w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w)) {
			if (visited[w] == 0) {
				visit(G, w);
				visited[w] = 1;
				enQueue(&Q, w);
			}
		}
	}
}
// 广度优先遍历 主函数
void BFSTraverse(MGraph G) {
	for (int i = 0; i < G->vexnum; ++i) {
		visited[i] = 0;
	}
	LinkQueue Q;
	initQueue(&Q);
	for (int i = 0; i < G->vexnum; ++i) {
		if (visited[i] == 0)
			BFS(G, Q, i);
	}
}
// 深度优先遍历
void DFS(MGraph G, int v) {
	visit(G, v);
	visited[v] = 1;
	for (int w = firstNeighbor(G, v); w >= 0; w = nextNeighbor(G, v, w)) {
		if (visited[w] == 0)
			DFS(G, w);
	}
}
// 深度优先遍历 主函数
void DFSTraverse(MGraph G) {
	for (int i = 0; i < G->vexnum; ++i) {
		visited[i] = 0;
	}
	for (int i = 0; i < G->vexnum; ++i) {
		if (visited[i] == 0)
			DFS(G, i);
	}
}


int main() {
	MGraph G = initGraph();
	printGraph(G);

	printf("\n广度优先遍历 : ");
	BFSTraverse(G);

	printf("\n深度优先遍历 : ");
	DFSTraverse(G);
	return 0;
}

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

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

相关文章

使用 MCSM 面板一键搭建我的世界服务器,并内网穿透公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 转载自远程穿透文章&…

【AI】Stable-Diffusion-WebUI使用指南

注&#xff1a;csdn对图片有审核&#xff0c;审核还很奇葩&#xff0c;线稿都能违规&#xff0c;为保证完整的阅读体验建议移步至个人博客阅读 最近AI绘画实现了真人照片级绘画水准&#xff0c;导致AI绘画大火&#xff0c;公司也让我研究研究&#xff0c;借此机会正好了解一下…

图像处理:GrapeCity Documents Imaging 6.1.2 Crack

适用于 .NET 6 的快速、强大的映像 API 库,在代码中应用高级图像处理&#xff0c;零依赖关系。 加载和保存图像文件&#xff0c;如BMP&#xff0c;JPEG&#xff0c;TIFF&#xff0c;GIF&#xff0c;ICO&#xff0c;SVG&#xff0c;WebP和PNG 对灰度和 RGB 图像应用抖动和阈值等…

Ribbon 负载均衡策略 —— 图解、源码级解析

文章目录 负载均衡策略RandomRuleRoundRobinRuleRetryRuleWeightedResponseTimeRuleBestAvailableRuleAvailabilityFilteringRuleZoneAvoidanceRule Ribbon 负载均衡策略源码RandomRule源码RoundRobinRule源码BestAvailableRule源码RetryRule源码 通过本文你可以学习到&#xf…

自学大语言模型之BERT

BERT 模型由 Jacob Devlin、Ming-Wei Chang、Kenton Lee 和 Kristina Toutanova在BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding中提出。它是一种双向变换器&#xff0c;使用掩码语言建模目标和对包含多伦多图书语料库和维基百科的大型语…

开源高星精选,10个2023企业级Python测试项目,再不学习时间就没了

纸上得来终觉浅&#xff0c;光学习理论知识是不够的。 想要学好软件测试必须要结合实战项目深入掌握&#xff0c;今天给大家分享十个2022最新企业级Python软件测试项目&#xff1a; ​ 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; ▌Rank 1&#xf…

SEW-Movifit软件的调试步骤

首先安装软件&#xff08;名称和版本为SEW_Software_MotionStudio_V5-9-0-4-compact&#xff09;。安装完毕后打开软件&#xff0c;新建一个工程。 3、新建完成之后会进入如下画面。 4、点击红框内的图标进行设置 5、打开后会显示如下画面&#xff0c;在下拉菜单中选择serial这…

【Unity3D】高斯模糊特效

1 高斯模糊原理 边缘检测特效中使用了卷积运算进行了边缘检测&#xff0c;本文实现的高斯模糊特效同样使用了卷积运算&#xff0c;关于卷积核和卷积运算的概念&#xff0c;读者可以参考边缘检测特效。 本文完整资源见→Unity3D高斯模糊特效。 我们将用于模糊处理的卷积核称为模…

C++模拟牛顿力学(2D)

简介 如何用计算机来模拟真实世界呢&#xff1f;计算机最大的功能是计算&#xff0c;而物理学的种种公式就把现实世界中的物理规律以数学的语言描绘了出来&#xff0c;从而使我们可以通过计算大致模拟现实世界的物体运动。因此不难想到把物理学定律&#xff08;这里用的是牛顿…

SAP-MM-维护物料主数据的类(Class)和特性(Characteristic)

一&#xff0e;说明 物料主数据有千个左右条目&#xff0c;但仍不能满足各类物料自有特性的描述&#xff0c;为此SAP启用了类&#xff08;Class&#xff09;和特性&#xff08;Characteristic&#xff09;&#xff0c;并在物料主数据的分类视图&#xff08;Characteristic&…

推荐一款免费开源的代码质量分析工具

文章目录 一、简介二、环境安装三、使用说明四、其他报错UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe6 in position 29: ordinal not in range(128)**linux:****windos:** 五、安全编程规范 一、简介 Flawfinder是一款开源的关于C/C静态扫描分析工具&#xf…

C++入门——关键字|命名空间|输入输出

前言&#xff1a; 今天我们又开启了一个崭新的大门——C面向对象编程语言&#xff0c;C是怎么来的呢&#xff1f;答案是&#xff1a;因为C语言的有很多不足&#xff0c;我们的祖师爷用着不爽&#xff0c;就不断更改&#xff0c;就改出来了一门新的语言&#xff0c;C。C语言兼容…

黑客常用的十大工具(附工具安装包),你知道几款?

注&#xff1a;本文总结白帽黑客常用的十大工具。文档仅供参考&#xff0c;不得用于非法用途&#xff0c;否则后果自负。 1 Nmap nmap是一个网络连接端扫描软件&#xff0c;用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端&#xff0c;并且推断计算机运行哪个…

谈谈开源的利弊和国内的开源 ——《新程序员005:开源深度指南 新金融背后的科技力量》书评

感谢CSDN的送测 《新程序员005&#xff1a;开源深度指南 & 新金融背后的科技力量》 是一本以计算机编程和金融科技为主题的杂志书&#xff0c;由中国最大的开源社区之一的开源社主办&#xff0c;内容丰富多样&#xff0c;包括了众多知名开源项目和工具的介绍&#xff0c;同…

第 3 章:使用 Vue 脚手架

目录 具体步骤 模板项目的结构&#xff08;脚手架文件结构&#xff09; Vue脚手架报错 修改方案&#xff1a; 关于不同版本的Vue vue.config.js配置文件 ref属性 props配置项 mixin(混入) 插件 小结&#xff1a; scoped样式 小结&#xff1a; Todo-list 案例 小结…

kafka重点问题解答-----kafka 的设计架构

1. kafka 都有哪些特点&#xff1f; 高吞吐量&#xff0c;低延迟 可以热扩展 并发度高 具有容错性(挂的只剩1台也能正常跑) 可靠性高 2. 请简述你在哪些场景下会选择 kafka&#xff1f; kafka的一些应用 日志收集&#xff1a;一个公司可以用kafka可以收集各种服务的log&…

自学黑客(网络安全/web渗透),一般人我还是劝你算了吧

由于我之前写了不少网络安全技术相关的文章&#xff0c;不少读者朋友知道我是从事网络安全相关的工作&#xff0c;于是经常有人私信问我&#xff1a; 我刚入门网络安全&#xff0c;该怎么学&#xff1f; 要学哪些东西&#xff1f; 有哪些方向&#xff1f; 怎么选&a…

chatgpt赋能python:Python分解三位数:打造高效的数学学习工具

Python分解三位数&#xff1a;打造高效的数学学习工具 介绍 Python是一种动态、解释型、高级编程语言&#xff0c;广泛应用于数据分析、人工智能、机器学习等领域。在数学教育中&#xff0c;Python也是一个非常好的工具&#xff0c;可以帮助学生更好地理解数学知识和提高解题…

Linux内核模块开发 第 6 章

The Linux Kernel Module Programming Guide Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang译 断水客&#xff08;WaterCutter&#xff09; 6 字符设备驱动 include/linux/fs.h 中定义了结构体 file_operations &#xff0c;这个结构体包含指…

深度学习论文分享(三)Look More but Care Less in Video Recognition(NIPS2022)

深度学习论文分享&#xff08;三&#xff09;Look More but Care Less in Video Recognition&#xff08;NIPS2022&#xff09; 前言Abstract1. Introduction2 Related Work2.1 Video Recognition2.2 Redundancy in Data&#xff08;数据冗余&#xff09; 3 Methodology3.1 Arc…