【数据结构】无向图创建邻接矩阵、深度优先遍历和广度优先遍历(C语言版)

无向图创建邻接矩阵、深度优先遍历和广度优先遍历
  • 一、概念解析:
    • (1)无向图:
    • (2)邻接矩阵:
  • 二、创建邻接矩阵:
  • 三、深度遍历、广度遍历
    • (1)深度遍历概念:
    • (2)广度遍历概念:
  • 四、实例展示

一、概念解析:

(1)无向图:

假设图G由两个集合V和E组成,记为G={V , E}。其中V是顶点的有限集合,E是连接V中两个不同顶点的边的有限集合。如果E中的顶点对是有序的,即E中的每条边都是有方向的,则称G是有向图。如果顶点对是无序的,则称G是无向图

在这里插入图片描述

在这里插入图片描述

(2)邻接矩阵:

邻接矩阵主要由:二维数组 实现

如图
在这里插入图片描述

转换成邻接矩阵为:

在这里插入图片描述

二、创建邻接矩阵:

基本每一步都有注释,详细观看,建议画图理解

代码如下:

#define MAXSIZE 100 
//	邻接矩阵 
typedef struct Matrix{int V_Data;		//	顶点数据域 int E_Data;		//	边数数据域int Node[MAXSIZE];	//	存放顶点数据,也就是顶点表 int Weight[MAXSIZE][MAXSIZE]; 	//	存放权重,为矩阵中两点有边的标记符号 }MaTrix,*MATRIX;//	邻接矩阵数据结构体 
typedef struct Edge{int v1;		//	用来存放第一个顶点 int v2;		//	用来存放第二个顶点int weight;	//	用来存放两点之间的标记符,即为权 
}*EDGE;//******************** 邻接矩阵*******************//
//	邻接矩阵、顶点和边初始化 
void Init_Matrix(MATRIX S,int Vertex)
{	S->E_Data = 0;			//	初始化为0条边 S->V_Data = Vertex;		//	初始化顶点数 int i,j;for(i=0;i<Vertex;i++){for(j=0;j<Vertex;j++){S->Weight[i][j] = 0;}} 
}//	开始插入边的权重,即为两个顶点之间边的标记符
void InSerData(MATRIX S,EDGE E)
{//	将输入的顶点v1、v2之间的边,用权作为标记,在矩阵中表示//	这里是无向图,所以边没有方向,需要做标记两次(为v1-v2和v2-v1) S->Weight[E->v1][E->v2] = E->weight;	 S->Weight[E->v2][E->v1] = E->weight; 
} //	开始插入数据 
void InSerEdge_Data(MATRIX S,int edge,int V)
{int i,j;if(edge>0)	//	边数大于0的时候才插入数据 {printf("请输入顶点和权重(空格分隔!)\n");for(i=0;i<edge;i++){		EDGE E;				//分配内存,接受顶点v1,v2和权重(标记符)	E = (EDGE)malloc(sizeof(struct Edge));	scanf("%d %d %d",&(E->v1),&(E->v2),&(E->weight));if(E->v1 ==E->v2){printf("无向图邻接矩阵对角线为0,输入错误,结束运行\n");exit(-1); }InSerData(S,E);}	printf("请输入要定义的顶点,填入顶点表中: \n");for(j=0;j<V;j++){scanf("%d",&(S->Node[j]));}		}else{	printf("输入的边数错误"); } 		
} 

三、深度遍历、广度遍历

(1)深度遍历概念:

在这里插入图片描述

在这里插入图片描述

定义的结构体、数组可看上面代码

深度遍历代码解析:

//*****************	深度优先遍历算法—邻接矩阵 *****************//
void DFS_Begin(MATRIX P,int k,int V)
{int i;flag[k] = 1;	//标记当前顶点,表示已经遍历过printf("%d ",P->Node[k]);	//	输出当前顶点 for(i=0;i<V;i++){if(!flag[i] && P->Weight[k][i] != 0)//	如果当前顶点的邻近点存在,且没有遍历过 {									//	则继续递归遍历 DFS_Begin(P,i,V);		//	递归遍历当前顶点的邻近点 }	} 
}void Init_DFSMatrix(MATRIX P,int V)
{int i;//	初始化标记符数组,全为0 for(i=0;i<V;i++){flag[i] = 0;}for(i=0;i<V;i++)	//	每个顶点都要检查是否遍历到 {if(!flag[i])	//	排除遇到已经遍历的顶点DFS_Begin(P,i,V);		//	开始深度遍历	} putchar('\n');	
}

(2)广度遍历概念:

在这里插入图片描述

这里使用到了链队列(也可以使用数组队列,看个人想法),可以看我之前的博文有讲:

//******************** 队列 *****************//
typedef struct Queue{int data[MAXSIZE];	//	队列大小 int head;	//	队头 int wei;	//	队尾 }Queue; //*****************	队列 *************************************//
//	队列初始化 
void InitQueue(Queue *q)
{q->head= 0;		//	初始化队头、队尾 q->wei = 0;
} //	判断队列是否为空
int EmptyQueue(Queue *q)
{if(q->head == q->wei)return 1;else{return 0;}		
} //	入队
void PushQueue(Queue *q,int t)
{if((q->wei+1)%MAXSIZE == q->head)	//	说明队列已经满了return;else{	q->data[q->wei] = t;	q->wei = (q->wei +1)%MAXSIZE;	//	队尾后移 }} //	出队
void PopQueue(Queue *q,int *x)
{if(q->wei == q->head)	//	出队完毕 return;	else{	 	*x = q->data[q->head];q->head = (q->head + 1)%MAXSIZE; //	队头后移	}	} //***************** 广度优先搜索算法—邻接矩阵 ****************//
void Init_Bfs(MATRIX S,int V)
{int i,j;int k;Queue Q;for(i=0;i<V;i++){Vist[i] = 0;	//	初始化标记符 }InitQueue(&Q);	//	队列初始化 for (i = 0; i < V; i++){if (!Vist[i])	//	判断以这个顶点为基准,有连接的其他顶点 {Vist[i] = 1;	//	标记遍历的这个顶点 printf("%d ", S->Node[i]);PushQueue(&Q, i);	//	入队 while (!EmptyQueue(&Q))	//	队列中还有数据,说明这个顶点连接的其他顶点还没有遍历完 {PopQueue(&Q,&i);	//	出队 for (j = 0; j < V; j++){//	以这个顶点为基准,遍历其他连接的顶点 if (!Vist[j] && S->Weight[i][j] != 0){Vist[j] = 1;	//	与之连接的顶点作上标记,便于后序顶点跳过相同的遍历 printf("%d ", S->Node[j]);//	输出与之相邻连接的顶点 PushQueue(&Q, j);	//	让与之连接的顶点其位置入队 }}}}}
} 

四、实例展示

注意:这里存入数据时,坐标点以原点(0,0)为起点开始!

以这个图为样例展示:

在这里插入图片描述

全部代码:

#include<stdio.h>
#include<stdlib.h>#define MAXSIZE 100 //	深度遍历标记符
int flag[MAXSIZE]; 		//	邻接矩阵 //	广度优先遍历标记符 
int Vist[MAXSIZE]; 		//	邻接矩阵//******************** 队列 *****************//
typedef struct Queue{int data[MAXSIZE];	//	队列大小 int head;	//	队头 int wei;	//	队尾 }Queue; //	邻接矩阵 
typedef struct Matrix{int V_Data;		//	顶点数据域 int E_Data;		//	边数数据域int Node[MAXSIZE];	//	存放顶点数据,也就是顶点表 int Weight[MAXSIZE][MAXSIZE]; 	//	存放权重,为矩阵中两点有边的标记符号 }MaTrix,*MATRIX;//	邻接矩阵数据结构体 
typedef struct Edge{int v1;		//	用来存放第一个顶点 int v2;		//	用来存放第二个顶点int weight;	//	用来存放两点之间的标记符,即为权 
}*EDGE;//******************** 邻接矩阵*******************//
//	邻接矩阵、顶点和边初始化 
void Init_Matrix(MATRIX S,int Vertex)
{	S->E_Data = 0;			//	初始化为0条边 S->V_Data = Vertex;		//	初始化顶点数 int i,j;for(i=0;i<Vertex;i++){for(j=0;j<Vertex;j++){S->Weight[i][j] = 0;}} 
}//	开始插入边的权重,即为两个顶点之间边的标记符
void InSerData(MATRIX S,EDGE E)
{//	将输入的顶点v1、v2之间的边,用权作为标记,在矩阵中表示//	这里是无向图,所以边没有方向,需要做标记两次(为v1-v2和v2-v1) S->Weight[E->v1][E->v2] = E->weight;S->Weight[E->v2][E->v1] = E->weight; 
} //*****************	深度优先遍历算法—邻接矩阵 *****************//
void DFS_Begin(MATRIX P,int k,int V)
{int i;flag[k] = 1;	//标记当前顶点,表示已经遍历过printf("%d ",P->Node[k]);	//	输出当前顶点 for(i=0;i<V;i++){if(!flag[i] && P->Weight[k][i] != 0)//	如果当前顶点的邻近点存在,且没有遍历过 {									//	则继续递归遍历 DFS_Begin(P,i,V);		//	递归遍历当前顶点的邻近点 }	} 
}void Init_DFSMatrix(MATRIX P,int V)
{int i;//	初始化标记符数组,全为0 for(i=0;i<V;i++){flag[i] = 0;}for(i=0;i<V;i++)	//	每个顶点都要检查是否遍历到 {if(!flag[i])	//	排除遇到已经遍历的顶点DFS_Begin(P,i,V);		//	开始深度遍历	} putchar('\n');}//*****************	队列 *************************************//
//	队列初始化 
void InitQueue(Queue *q)
{q->head= 0;		//	初始化队头、队尾 q->wei = 0;
} //	判断队列是否为空
int EmptyQueue(Queue *q)
{if(q->head == q->wei)return 1;else{return 0;}		
} //	入队
void PushQueue(Queue *q,int t)
{if((q->wei+1)%MAXSIZE == q->head)	//	说明队列已经满了return;else{	q->data[q->wei] = t;	q->wei = (q->wei +1)%MAXSIZE;	//	队尾后移 }} //	出队
void PopQueue(Queue *q,int *x)
{if(q->wei == q->head)	//	出队完毕 return;	else{*x = q->data[q->head];q->head = (q->head + 1)%MAXSIZE; //	队头后移}	} //***************** 广度优先搜索算法—邻接矩阵 ****************//
void Init_Bfs(MATRIX S,int V)
{int i,j;int k;Queue Q;for(i=0;i<V;i++){Vist[i] = 0;	//	初始化标记符 }InitQueue(&Q);	//	队列初始化 for (i = 0; i < V; i++){if (!Vist[i])	//	判断以这个顶点为基准,有连接的其他顶点 {Vist[i] = 1;	//	标记遍历的这个顶点 printf("%d ", S->Node[i]);PushQueue(&Q, i);	//	入队 while (!EmptyQueue(&Q))	//	队列中还有数据,说明这个顶点连接的其他顶点还没有遍历完 {PopQueue(&Q,&i);	//	出队 for (j = 0; j < V; j++){//	以这个顶点为基准,遍历其他连接的顶点 if (!Vist[j] && S->Weight[i][j] != 0){Vist[j] = 1;	//	与之连接的顶点作上标记,便于后序顶点跳过相同的遍历 printf("%d ", S->Node[j]);//	输出与之相邻连接的顶点 PushQueue(&Q, j);	//	让与之连接的顶点其位置入队 }}}}}
} //	初始化顶点个数 
int Init_Vertex()
{int Vertex;printf("请输入顶点个数: ");scanf("%d",&Vertex);return Vertex;
}//	初始化边的数量 
int Init_Edge()
{int edge;printf("请输入边的数量: ");scanf("%d",&edge);return edge;} //	开始插入数据 
void InSerEdge_Data(MATRIX S,int edge,int V)
{int i,j;if(edge>0)	//	边数大于0的时候才插入数据 {printf("请输入顶点和权重(空格分隔!)\n");for(i=0;i<edge;i++){		EDGE E;				//分配内存,接受顶点v1,v2和权重(标记符)	E = (EDGE)malloc(sizeof(struct Edge));	scanf("%d %d %d",&(E->v1),&(E->v2),&(E->weight));if(E->v1 ==E->v2){printf("无向图邻接矩阵对角线为0,输入错误,结束运行\n");exit(-1); }InSerData(S,E);}	printf("请输入要定义的顶点,填入顶点表中: \n");for(j=0;j<V;j++){scanf("%d",&(S->Node[j]));}}else{printf("输入的边数错误"); } } //	打印无向图邻接矩阵 
void Show_Matrix(MATRIX p,int Vertex)
{int i,j;for(i=0;i<Vertex;i++){for(j=0;j<Vertex;j++){printf("%4d",p->Weight[i][j]);	//	打印邻接矩阵 }	putchar('\n');	//	换行 }
}int main()
{int val;int Vertex;int edge;MATRIX p;		//	邻接矩阵头节点指针//	创建无向图邻接矩阵 					Vertex = Init_Vertex();edge = Init_Edge();p = (MATRIX)malloc(sizeof(MaTrix));		//分配内存空间 p->V_Data = Vertex;		//	记录顶点个数 p->E_Data = edge;		//	记录边的个数 Init_Matrix(p,Vertex);	//	初始化邻接矩阵 InSerEdge_Data(p,edge,Vertex);	//	插入数据 //	打印无向图的邻接矩阵 printf("无向图邻接矩阵如下:");	printf("\n----------------------------------\n\n");Show_Matrix(p,Vertex);printf("\n----------------------------------\n");//	深度优先遍历—邻接矩阵	printf("深度遍历—邻接矩阵结果为:\n");Init_DFSMatrix(p,Vertex);//	广度优先遍历—邻接矩阵printf("广度优先遍历—邻接矩阵结果为: \n");Init_Bfs(p,Vertex);return 0;	
} 

结果图:
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

学习笔记18:Codeforces Round 923 (Div. 3)

D 预处理&#xff0c;ans[i]记录一a[i]后面第一个与a[i]相等的值&#xff08;如果没有&#xff0c;则需要特殊判断或者初始化成一个极大值&#xff09; 每次询问时&#xff0c;可以直接看ans[l]是否大于r&#xff0c;如果大于则不存在&#xff0c;如果小于则存在 #include&l…

用HTML5实现动画

用HTML5实现动画 要在HTML5中实现动画&#xff0c;可以使用以下几种方法&#xff1a;CSS动画、使用<canvas>元素和JavaScript来实现动画、使用JavaScript动画库。重点介绍前两种。 一、CSS动画 CSS3 动画&#xff1a;使用CSS3的动画属性和关键帧&#xff08;keyframes&…

Fluke ADPT 连接器新增对福禄克万用 Fluke 17B Max 的支持

所需设备&#xff1a; 1、Fluke ADPT连接器&#xff1b; 2、Fluke 17B Max&#xff1b; Fluke 17B Max拆机图&#xff1a; 显示界面如下图&#xff1a; 并且可以将波形导出到EXCEL: 福禄克万用表需要自己动手改造&#xff01;&#xff01;&#xff01;

Spring Boot 笔记 020 redis集成

1.1 安装redis Windows 下 Redis 安装与配置 教程_redis windows-CSDN博客 2.1 引入redis坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 2.2 配置…

无人机导航技术,无人机导航理论基础,无人机导航技术应用发展详解

惯性/卫星定位组合是一种比较理想的组合导航系统。在无人机导航领域&#xff0c;多年来惯性/卫星定位组合导航系统的研究一直受到普遍的关注&#xff0c;大量的理论研究成果得到实际应用。 常见的几类导航系统 单一导航 卫星导航系统 、多普勒导航、惯性导航系统(INS) 、图形…

【Java多线程】对进程与线程的理解

目录 1、进程/任务&#xff08;Process/Task&#xff09; 2、进程控制块抽象(PCB Process Control Block) 2.1、PCB重要属性 2.2、PCB中支持进程调度的一些属性 3、 内存分配 —— 内存管理&#xff08;Memory Manage&#xff09; 4、线程&#xff08;Thread&#xff09;…

阿里云幻兽帕鲁服务器更新了1.4之后,进游戏要重新创建角色,怎么解决?

阿里云幻兽帕鲁服务器更新了1.4之后&#xff0c;进游戏要重新创建角色&#xff0c;怎么解决&#xff1f; 其实这个问题的主要原因可能还是因为前后的APPID不一致导致。 因为Palworld服务端有两种&#xff0c;一种是有APPID&#xff0c;还有一种是没有APPID。 参考这篇教程&am…

曝某头部电商企业急招鸿蒙开发高手 年薪超过百万

近日某头部电商企业急需鸿蒙开发高手&#xff0c;提供高达100万的年薪&#xff0c;工作地点位于北京。 随着鸿蒙生态不断发展壮大&#xff0c;越来越多的企业开始加入其中&#xff0c;对鸿蒙OS开发工程师的需求也越来越迫切。据新浪科技报道&#xff0c;多家互联网公司相继发布…

cefsharp121(cef121.3.7Chromium121.0.6167.160)升级测试及其他H264版本

一、版本说明 1.1 本此版本 此版本CEF 121.3.7+g82c7c57+chromium-121.0.6167.160 / Chromium 121.0.6167.160 1.2 其他支持H264版本 支持H264推荐版本:V100,V109,V111,V119版本,其他V114,V115,V108,V107 支持win7/win8/win8.1最后版本v109.x 支持NET4.5.2最后版本v114.x …

如何合理评估信号过孔的残桩效应--Via Stub

设计中&#xff0c;之所以会去考察信号过孔的残桩效应&#xff08;Via Stub&#xff09;&#xff0c;是因为它的存在导致了不需要的频率谐振&#xff0c;当这些谐振出现在所关注的信号通道的插入损耗中时&#xff0c;就会引发较为严重的信号完整性&#xff08;SI&#xff09;问…

Python 字符串格式化输出

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 前言 字符串格式化是编程中一个常见的需求&#xff0c;它可以们将不同类型的数据&#xff08;如数字、文本、日…

JVM-JVM中对象的生命周期

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 原资料地址&#xff1a;课程资料 对象的创建 常量池检查:检查new指令是否能在常量池…

openEuler 22.03 LTS 上源码安装 PostgreSQL 15

安装PostgreSQL 15 1 安装必要的依赖 #yum install -y readline-devel zlib-devel gcc2、下载源码 # wget https://ftp.postgresql.org/pub/source/v15.6/postgresql-15.6.tar.gz # tar -xzvf postgresql-15.6.tar.gz3 配置 # cd postgresql-15.6/ # ./configure4 编译安装…

Matlab|基于支持向量机的电力短期负荷预测【三种方法】

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序主要是对电力短期负荷进行预测&#xff0c;采用三种方法&#xff0c;分别是最小二乘支持向量机&#xff08;LSSVM&#xff09;、标准粒子群算法支持向量机和改进粒子群算法支持向量机三种方法对负荷进行…

讲解用Python处理Excel表格

我们今天来一起探索一下用Python怎么操作Excel文件。与word文件的操作库python-docx类似&#xff0c;Python也有专门的库为Excel文件的操作提供支持&#xff0c;这些库包括xlrd、xlwt、xlutils、openpyxl、xlsxwriter几种&#xff0c;其中我最喜欢用的是openpyxl&#xff0c;这…

【计算机网络】物理层|传输介质|物理层设备|宽带接入技术

目录 一、思维导图 二、传输介质 1.传输介质——导引型 2.传输介质——非导引型​编辑 三、物理层设备 1.物理层设备&#xff1a;中继器&集线器 2.宽带接入技术&#xff08;有线&#xff09; ​编辑 四、趁热打铁☞习题训练 五、物理层总思维导图 推荐 前些天发现…

【C++】友元、内部类和匿名对象

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 1. 友元 1.1 友元函数 1.2 友元类 2. 内部类 2.1 成员内部类 2.2 局部内部类 3. 匿名对象 3.1 基本概念 3.1 隐式转换 1…

在已有代码基础上创建Git仓库

在已有代码基础上创建Git仓库 背景方法处理问题 背景 先进行了代码编写&#xff0c;后续想放入仓库方便大家一起合作开发&#xff0c;此时需要在已有代码的基础上建立仓库。 方法 首先在Gitee或者GitHub上创建仓库&#xff0c;这里以Gitee为例。创建完后&#xff0c;我们可以…

各类有关于花卉的深度学习数据集

花卉的识别和分类在深度学习过程中是最常见的使用的案例&#xff0c;因此各类有关花卉分类、识别、计数的图像数据集是大家都常用的数据集。最近收集到各类有关花卉的各类数据集分享给大家&#xff01;&#xff01; 1、16种花常见的图像数据集 数据说明&#xff1a;我们看到我…

Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务

目录: OpenID 与 OAuth2 基础知识Blazor wasm Google 登录Blazor wasm Gitee 码云登录Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务Blazor SSR/WASM IDS/OIDC 单点登录授权实例2-登录信息组件wasmBlazor SSR/WASM IDS/OIDC 单点登录授权实例3-服务端…