图的操作实验

图的操作

一、 实验目的

(1)掌握图的邻接矩阵和邻接表存储结构。

(2)熟练图的邻接表的基本运算。

(3)加深图的深度优先遍历算法和广度优先遍历算法的理解。

(4)领会最小生成树和最短路径问题的求解及相关算法设计。

二、 实验要求

有下图所示的带权有向图及其对应的邻接矩阵,编写一个程序,实现图的各种基本运算和下面main函数中的每一步功能。

(1)依据所给的邻接矩阵,创建上图的邻接表存储,并输出邻接表结构;

(2)输出从顶点0出发的一个深度优先遍历序列

(3)输出从顶点0出发的一个广度优先遍历序列

(4)采用克鲁斯卡尔算法求顶点0出发的一棵最小生成树

(5)采用克鲁斯卡尔算法求顶点0出发的一棵最小生成树

(6)采用迪杰斯特拉算法求顶点0出发到达其他各顶点的最短路径及最短路径长度

7)销毁图的邻接表

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<malloc.h>
#include<string.h>
typedef char InfoType;
using namespace std;
typedef int ElemType;
using namespace std;
#define MAXY 5
#define INF 32767 // 无穷
#define MaxSize 1000

typedef struct {
	int u; // 边的起始顶点
	int v; // 边的终止顶点
	int w; // 边的权值
} Edge;

typedef struct {
	int n; // 图的顶点数
	int e; // 图的边数
	int edges[MAXY][MAXY]; // 邻接矩阵表示图的边
} MatGraph;

typedef struct ANode
{
	int adjvex;//该边邻接点编号
	struct ANode* nextarc;//指向下一条边的指针
	int weight;//该边的相关信息,例如权值

}ArcNode;
typedef struct Vnode
{
	InfoType data;//顶点其他信息
	ArcNode* firstarc;//指向第一个边结点
}VNode;
typedef struct
{
	VNode adjlist[MAXY];
	int n, e;
}AdjGraph;

void CreateAdj(AdjGraph *&G, int A[MAXY][MAXY], int n, int e)//创建图的邻接表
{
	int i, j; ArcNode* p;
	G = (AdjGraph*)malloc(sizeof(AdjGraph));
	for (i = 0; i < n; i++)
		G->adjlist[i].firstarc = NULL;//所有头结点指针域置为空
	for (i = 0; i < n; i++)//遍历邻接矩阵
	{
		for (j = n - 1; j >= 0; j--)
		{
			if (A[i][j] != 0 && A[i][j] != INF)//存在一条边<i,j>
			{
				p = (ArcNode*)malloc(sizeof(ArcNode));//创建一个结点p
				p->adjvex = j;//存放邻接点
				p->weight = A[i][j];//存放权
				p->nextarc = G->adjlist[i].firstarc;//采用头插法插入结点p
				G->adjlist[i].firstarc = p;
			}
		}
		G->n = n; G->e = e;
	}
}//创建图的邻接表
void DispAdj(AdjGraph* G)
{
	int i; ArcNode* p;
	for (i = 0; i < G->n; i++)
	{
		p=G->adjlist[i].firstarc;
		printf("%3d:", i);
		while (p != NULL)
		{
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}//输出邻接表G
void DestroyAdj(AdjGraph*& G)
{
	int i; ArcNode* pre, * p;
	for (i = 0; i < G->n; i++)
	{
		pre = G->adjlist[i].firstarc;//p指向第i个单链表头结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}
	free(G);//释放头结点数组
}//销毁图
int visited[MAXY] = { 0 };
void DFS(AdjGraph* G, int v)
{
	ArcNode* p;
	visited[v] = 1;//置已访问标记
	printf("%d ", v);//输出被访问顶点的编号
	p = G->adjlist[v].firstarc;//p指向顶点v的第一个邻接点
	while (p != NULL)
	{
		if (visited[p->adjvex] == 0)//若p->adjvex顶点未被访问,递归访问它
			DFS(G, p->adjvex);
		p = p->nextarc;//p指向顶点v的下一个邻接点
	}
}//深度优先遍历





typedef struct
{
	ElemType data[MaxSize];
	int front, rear;
}SqQueue;
//(1)初始化环形队列
void InitQueue(SqQueue*& q)
{
	q = (SqQueue*)malloc(sizeof(SqQueue));
	q->front = q->rear = 0;
}
//(2)依次进队元素
bool enQueue(SqQueue*& q, ElemType e)
{
	if ((q->rear + 1) % MaxSize == q->front)
		return false;
	q->rear = (q->rear + 1) % MaxSize;
	q->data[q->rear] = e;
	return true;
}
//(3)判断环形队列q是否非空
bool QueueEmpty(SqQueue* q)
{
	return(q->front == q->rear);
}

//(4)出队一个元素,输出该元素
bool deQueue(SqQueue*& q, ElemType& e)
{
	if (q->front == q->rear)
		return false;
	q->front = (q->front + 1) % MaxSize;
	e = q->data[q->front];
	return true;
}


void BFS(AdjGraph* G,int u, int v)
{
	int w, i; ArcNode* p;
	SqQueue* qu;//定义环形队列指针
	InitQueue(qu);//初始化队列
	int visited[MAXY];//定义顶点访问标记数组
	for (i = 0; i < G->n; i++)
		visited[i] = 0;//访问标记数组初始化
	printf("%2d", v);//输出访问顶点编号
	visited[v] = 1;//设置已访问标记
	enQueue(qu, v);
	while (!QueueEmpty(qu))//队不空循环
	{
		deQueue(qu, w);//出队一个顶点w
		p = G->adjlist[w].firstarc;//指向w的第一个邻接点
		while (p != NULL)//查找w所有的邻接点
		{
			if (visited[p->adjvex == 0])//如果该邻接点未被访问
			{
				printf("%2d", p->adjvex);//访问该邻接点
				visited[p->adjvex] = 1;//设置已访问标记
				enQueue(qu, p->adjvex);//该顶点进队
			}
			p = p->nextarc;//找下一个邻接点
		}
	}
	printf("\n");
}//广度优先遍历



void InsertSort(Edge arr[], int n) {
	int i, j;
	Edge key;
	for (i = 1; i < n; i++) {
		key = arr[i];
		j = i - 1;
		while (j >= 0 && arr[j].w > key.w) {
			arr[j + 1] = arr[j];
			j = j - 1;
		}
		arr[j + 1] = key;
	}
}

void Kruskal(MatGraph g) {
	int i, j, u1, v1, sn1, sn2, k;
	int vset[MAXY];
	Edge E[MaxSize]; // 存放图中的所有边
	k = 0; // E数组下标从0开始
	for (i = 0; i < g.n; i++) {
		for (j = 0; j < g.n; j++) {
			if (g.edges[i][j] != 0 && g.edges[i][j] != INF) {
				E[k].u = i;
				E[k].v = j;
				E[k].w = g.edges[i][j];
				k++;
			}
		}
	}
	InsertSort(E, g.e); // 采用直接插入排序法对E数组按权值递增排序
	for (i = 0; i < g.n; i++) {
		vset[i] = i; // 初始化辅助数组
	}
	k = 1; // k表示当前构造生成树的第几条边,初值为1
	j = 0; // E中边的下标,初值为0
	while (k < g.n) {
		u1 = E[j].u;
		v1 = E[j].v; // 取一条边的两个顶点
		sn1 = vset[u1];
		sn2 = vset[v1]; // 分别得到两个顶点所属的集合编号
		if (sn1 != sn2) {
			printf("(%d,%d):%d\n", u1, v1, E[j].w); // 输出最小生成树的一条边
			k++; // 生成的边数加1
			for (i = 0; i < g.n; i++) {
				if (vset[i] == sn2) { // 两个集合统一编号
					vset[i] = sn1;
				}
			}
		}
		j++; // 遍历下一条边
	}
}


void Ppath(int path[], int i, int v)
{
	int k;
	k = path[i];
	if (k == v)
		return;
	Ppath(path, k, v);
	printf("%d,", k);
}
void Dispath(int dist[], int path[], int s[], int n, int v) {
	for (int i = 0; i < n; i++) {
		if (s[i] == 1) { // 顶点i在S中,输出路径长度和路径信息。
			printf("从%d到%d的最短路径长度为:%d\t路径为:", v, i, dist[i]);
			printf("%d,", v);
			Ppath(path, i, v); // 打印从源点v到顶点i的路径。
			printf("%d\n", i);
		}
		else { // 顶点i不在S中,输出不存在路径的信息。
			printf("从%d到%d不存在路径\n", v, i);
		}
	}
}




void Dijkstra(MatGraph g, int v)
{
	int dist[MAXY], path[MAXY];
	int S[MAXY];//s[i]=1表示顶点i在S中,S[i]=0表示顶点i在U中
	int mindist, i, j, u;
	for (i = 0; i < g.n; i++)
	{
		dist[i] = g.edges[v][i];//距离初始化
		S[i] = 0;//将S[]置空
		if (g.edges[v][i] < INF)//路径初始化
			path[i] = v;//顶点v到顶点i有边时,设置顶点i的前一个顶点为v
		else
			path[i] = -1;//顶点v到顶点i没边时,设置顶点i的前一个顶点为-1
	}
	S[v] = 1; path[v] = v;//源点编号v放入S中
	for (i = 0; i < g.n - 1; i++)//循环,直到所有顶点的最短路径都求出
	{
		mindist = INF;//mindist置最大长度初值
		for (j = 0; j < g.n; j++)//选取不在S中(既U中)且具有最小最短路径长度顶点u
			if (S[j] == 0 && dist[j] < mindist)
			{
				u = j;
				mindist = dist[j];
			}
		S[u] = 1;//顶点u加入S中
		for (j = 0; j < g.n; j++)//修改不在S中(即U中)的顶点的最短路径
			if (S[j] == 0)
			{
				if (g.edges[u][j] < INF && dist[u] + g.edges[u][j] < dist[j])
				{
					dist[j] = dist[u] + g.edges[u][j];
					path[j] = u;
				}
			}
	}
	Dispath(dist, path, S, g.n, v);//输出最短路径
}



int main() {
	MatGraph g;
	g.n = 5; // 顶点数
	g.e = 5; // 边数
	int A[MAXY][MAXY] = {
		{0, 1, 2, 6, INF},
		{INF, 0, INF, 4, 5},
		{INF, INF, 0, INF, 3},
		{INF, INF, INF, 0, INF},
		{INF, INF, INF, 7, 0}
	};
	memcpy(g.edges, A, sizeof(A));
	AdjGraph* G;
	CreateAdj(G, A, 5, 7);
	printf("邻接表结构:\n");
	DispAdj(G);
	printf("深度优先遍历序列:\n");
	int visited[MAXY] = { 0 };
	DFS(G, 0);
	printf("\n");
	printf("广度优先遍历序列:\n");
	BFS(G, 0, 0);
	printf("克鲁斯卡尔算法最小生成树\n");
	Kruskal(g);
	Dijkstra(g, 0);
	printf("销毁图");
	DestroyAdj(G);
}

	


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

性能手机新标杆,一加 Ace 3 发布会定档 1 月 4 日

12 月 27 日&#xff0c;一加宣布将于 1 月 4 日发布新品一加 Ace 3。一加 Ace 系列秉持「产品力优先」理念&#xff0c;从一加 Ace 2、一加 Ace 2V 到一加 Ace 2 Pro&#xff0c;款款都是现象级爆品&#xff0c;得到了广大用户的认可与支持。作为一加 2024 开年之作&#xff0…

Leetcode 56 合并区间

题意理解&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。 合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组。 该数组需恰好覆盖输入中的所有区间 。 目标&#xff1a;合并…

踩坑RV1106板端部署rknn模型

文章目录 1、交叉编译2、板上跑通3、验证自己模型 1、交叉编译 官方给的一个流程: RKNN 模型推理测试为了避免踩坑在开头提出来 按照官方的流程可以跑通&#xff0c;他自己提供的yolov5s.rknn&#xff08;640*640&#xff09;的模型&#xff0c;但是跑自己的模型的时候加载就会…

ROS多机通信

1&#xff1a;安装ssh sudo apt-get install openssh-server ps -e|grep ssh2&#xff1a;网络静态IP设置 3&#xff1a;配置文件修改 sudo gedit /etc/hosts192.168.3.11 用户名 192.168.3.22 用户名另一台4&#xff1a;重启网络 sudo /etc/init.d/network-manager resta…

码住!8个小众宝藏的开发者学习类网站

1、simplilearn simplilearn是全球排名第一的在线学习网站&#xff0c;它的课程由世界知名大学、顶级企业和领先的行业机构通过实时在线课程设计和提供&#xff0c;其中包括顶级行业从业者、广受欢迎的培训师和全球领导者。 2、VisuAlgo VisuAlgo是一个免费的在线学习算法和数…

Python(九十二)函数的参数定义-个数可变的位置参数和个数可变的关键字形参

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

keil编译报错:No space in execution regions with .ANY selector matching

No space in execution regions with .ANY selector matching 出现该错误是因为内存溢出&#xff0c;没有更多的空间&#xff0c;可以从以下几点进行排查。 1、优化编译器的编译规则&#xff0c;配置成Level 3 最高级&#xff0c;但是会增加编译时间 Keil编译器提供了多种优…

力扣热题100道-双指针篇

文章目录 双指针283.移动零11.盛最多水的容器15.三数之和42.接雨水 双指针 283.移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 …

WPF+Halcon 培训项目实战(6):目标匹配助手

前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只做笔记分享&#xff0c;想要源码或者教学视频可以和他联系一下。 相关链接 微软系列技术教程 WPF 年度公益课程 Halcon开发 CSD…

日本it培训班,日本IT大体分几类?

日本是一个老龄化极其严重的国家&#xff0c;拜泡沫经济破灭后的经济停滞所赐&#xff0c;民众取得了节育方面的丰硕成果&#xff0c;然而当经济终于走出阴霾&#xff0c;呈现复苏迹象时&#xff0c;短缺的劳动力又成了一大问题&#xff0c;拖累整个经济的步伐。为了应对劳工市…

Pycharm引用其他文件夹的py

Pycharm引用其他文件夹的py 方式1&#xff1a;包名设置为Sources ROOT 起包名的时候&#xff0c;需要在该文件夹上&#xff1a;右键 --> Mark Directory as --> Sources ROOT 标记目录为源码目录&#xff0c;就可以了。 再引用就可以了 import common from aoeweb impo…

轻松部署、经济实惠:解密亚马逊云科技轻量应用服务器的魅力

近年来&#xff0c;云计算技术的迅猛发展为创业者提供了更便捷、经济实惠的基础设施解决方案。在众多云服务提供商中&#xff0c;亚马逊云科技的轻量应用服务器&#xff0c;即Amazon Lightsail&#xff0c;凭借其出色的性能、简单易用的界面和无缝的生态整合&#xff0c;成为许…

Java开发框架和中间件面试题(8)

目录 82.Mybatis一级缓存&#xff0c;二级缓存&#xff1f; 83.Mybatis如何防止SQL注入&#xff1f; 84.mybatis中resultType和resultMap有什么区别&#xff1f; 85.如何在SpringBoot中禁用Actuator断点安全性&#xff1f; 86.什么是SpringBoot&#xff1f;SpringBoot有哪些…

【docker实战】02 用docker安装mysql

本示例采用bitnami的镜像进行安装MySQL 一、镜像搜索 先搜索一下mysql有哪些镜像 [rootlocalhost ~]# docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql …

边缘计算网关在温室大棚智能控制系统应用,开启农业新篇章

项目需求 ●目前大棚主要通过人为手动控温度、控水、控光照、控风&#xff0c;希望通过物联网技术在保障产量的前提下&#xff0c;提高作业效率&#xff0c;降低大棚总和管理成本。 ●释放部分劳动力&#xff0c;让农户有精力管理更多大棚&#xff0c;进而增加农户收入。 ●…

Azure 学习总结

文章目录 1. Azure Function1.1 Azure Function 概念1.2 Azure Function 实现原理1.3 Azure Function 本地调试1.4 Azure Function 云部署 2. Azure API Managment 概念 以及使用2.1 Azure API 概念2.2 Azure API 基本使用 3. Service Bus 应用场景及相关特性3.1 Service Bus 基…

golang并发安全-sync.map

sync.map解决的问题 golang 原生map是存在并发读写的问题&#xff0c;在并发读写时候会抛出异常 func main() {mT : make(map[int]int)g1 : []int{1, 2, 3, 4, 5, 6}g2 : []int{4, 5, 6, 7, 8, 9}go func() {for i : range g1 {mT[i] i}}()go func() {for i : range g2 {mT[…

Flink1.17实战教程(第七篇:Flink SQL)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…

2023年12月27日学习记录_加入噪声

目录 1、今日计划学习内容2、今日学习内容1、add noise to audio clipssignal to noise ratio(SNR)加入 additive white gaussian noise(AWGN)加入 real world noises 2、使用kaggel上的一个小demo&#xff1a;CNN模型运行时出现的问题调整采样率时出现bug 3、明确90dB下能否声…

[递归回溯枚举] 装载问题

装载问题 题目描述 有一批共 n 个集装箱要装上 2 艘载重量分别为 c1和 c2的轮船&#xff0c;其中集装箱 i 的重量为 wi&#xff0c;且 装载问题要求确定&#xff0c;是否有一个合理的装在方案可将这 n 个集装箱装上这 2 艘轮船。如果有&#xff0c;找出最优装载方案。 关于输…