图的操作实验

news2024/11/28 1:54:05

图的操作

一、 实验目的

(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);
}

	


 

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

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

相关文章

Spring高手之路-Spring事务的传播机制(行为、特性)

目录 含义 七种事务传播机制 1.REQUIRED&#xff08;默认&#xff09; 2.REQUIRES_NEW 3.SUPPORTS 4.NOT_SUPPORTED 5.MANDATORY 6.NEVER 7.NESTED 含义 事务的传播特性指的是当一个事务方法被另一个事务方法调用时&#xff0c;这个事务方法应该如何进行&#xff1f; 七…

Clion 项目使用dbg-macro控制台输出ANSI转义,输出颜色文本。

#Clion如何输出ANSI转义 首先源于&#xff0c;引入dbg-macro后&#xff0c;运行发现控制台全部是 C:\Users\WuXiangGuJun\CodeSpace\ClionCodeProjects\Tina\cmake-build-debug\tests\tests.exe ?[02m[..a\tests\src\main.cpp:16 (main)] ?[0m?[36mmessage?[0m ?[01m&q…

【计算机网络实验】educoder实验八 IPV6网络及其路由 头歌

第一关 IPV6网络基础 //千万不要破坏文档原有结构与内容&#xff01;&#xff01;&#xff01; //以下均为判断题&#xff0c;F&#xff1a;表示错误&#xff0c;T&#xff1a;表示正确 //答案必须写在相应行末尾括号内&#xff0c;F与T二选一&#xff0c;大写 // 1、ipv6协议…

element el-table实现可进行横向拖拽滚动

【问题】表格横向太长&#xff0c;表格横向滚动条位于最底部&#xff0c;需将页面滚动至最底部才可左右拖动表格&#xff0c;用户体验感不好 【需求】基于elment的el-table组件生成的表格&#xff0c;使其可以横向拖拽滚动 【实现】灵感来源于这篇文章【Vue】表格可拖拽滚动&am…

《数据库开发实践》之触发器

一、什么是触发器&#xff1f; 1.概念&#xff1a; 简单来说触发器就是一种特殊的存储过程&#xff0c;在数据库服务器触发事件的时候会自动执行其SQL语句集。 2.构成四要素&#xff1a; &#xff08;1&#xff09;名称&#xff1a;要符合标识符命名规则 &#xff08;2&am…

idea 如何快速拉取新分支

方式1 &#xff08;快捷键&#xff1a;CtrlShift~&#xff09; 方式2:&#xff08;快捷键&#xff1a;Alt9&#xff09;

小梅哥Xilinx FPGA学习笔记18——专用时钟电路 PLL与时钟向导 IP

目录 一&#xff1a;IP核简介&#xff08;具体可参考野火FPGA文档&#xff09; 二&#xff1a; 章节导读 三&#xff1a;PLL电路原理 3.1 PLL基本实现框图 3.2 PLL倍频实现 3.3 PLL分频实现 四: 基于 PLL 的多时钟 LED 驱动设计 4.1 配置 Clocking Wizard 核 4.2 led …

详解结构体(包含结构体内存对齐,柔性数组,位段)【尊嘟很详细】

​ 结构体 结构体是一些值的集合&#xff0c;这些值称为成员变量&#xff0c;结构的成员可以是标量、数组、指针,甚至是其他结构体。 成员名可以与程序中其它变量同名&#xff0c;互不干扰。 结构体的定义 &#xff08;struct结构名{}&#xff09; struct books {int a;c…

Aseprite编译

官方网站 : https://www.aseprite.org/ Aseprite编译 步骤 : 1> App Store 下载安装 XCode 2> 安装 brew # /bin/bash -c "$(curl -fsSL https://gitee.com/ineo6/homebrew-install/raw/master/install.sh)" 或 # /bin/zsh -c "$(curl -fsSL https://g…

处理HTTP错误响应:Go语言中的稳健之道

开场白&#xff1a;在Web开发中&#xff0c;HTTP错误响应是不可避免的一部分。当请求无法成功完成时&#xff0c;服务器会返回一个错误响应。今天&#xff0c;我们将深入探讨如何在Go语言中优雅地处理这些HTTP错误响应。 知识点一&#xff1a;HTTP错误响应的常见类型HTTP错误响…

初步认识API安全

一、认识API 1. 什么是API API(应用程序接口)&#xff1a;是一种软件中介&#xff0c;它允许两个不相关的应用程序相互通信。它就像一座桥梁&#xff0c;从一个程序接收请求或消息&#xff0c;然后将其传递给另一个程序&#xff0c;翻译消息并根据 API 的程序设计执行协议。A…

使用spring boot实现异常的统一返回

在这个前后端分离的时代&#xff0c;一个 统一的数据格式非常重要。本次我们实现用spring boot实现一下返回给前端数据的统一格式&#xff0c;不再出现服务器500的错误。 新建一个spring boot项目&#xff0c;并导入knife4j的依赖。 写一个controller控制器&#xff0c;用来是…

JDK17:Java LinkedList源码解读

1. LinkedList简介 LinkedList是List接口的实现类&#xff0c;基于双向链表实现&#xff0c;继承自AbstractSequentialList类&#xff0c;同时也实现了Cloneable、Serializable接口。此外还实现了Queue和Deque接口&#xff0c;可以作为队列或双端队列使用。 LinkedList的插入删…

Starling-LM-7B与GPT-4:开源AI的新纪录

引言 在人工智能的前沿领域&#xff0c;Starling-LM-7B的出现标志着开源大型语言模型&#xff08;LLM&#xff09;的一大突破。与GPT-4的近距离竞争不仅展示了Starling-LM-7B的技术实力&#xff0c;也突显了开源社区在推动AI发展方面的重要作用。 模型特点 Starling-LM-7B&a…

算法学习系列(十五):最小堆、堆排序

目录 引言一、最小堆概念二、堆排序模板&#xff08;最小堆&#xff09;三、模拟堆 引言 这个堆排序的话&#xff0c;考的还挺多的&#xff0c;主要是构建最小堆&#xff0c;并且在很多情况下某些东西还用得着它来优化&#xff0c;比如说迪杰斯特拉算法可以用最小堆优化&#…

初识C语言·字符(串)函数

目录 1 字符分类函数 2 字符转换函数 3 strlen的模拟实现 4 strcpy的使用和模拟实现 5 strcat的使用和模拟实现 6 strcmp的使用和模拟实现 7 strncpy strncat strncmp的使用和模拟实现 8 strstr的使用和模拟实现 9 strerror的使用 10 strtok的使用 1 字符分类函数 C语…

Java ArrayList在遍历时删除元素

文章目录 1. Arrays.asList()获取到的ArrayList只能遍历&#xff0c;不能增加或删除元素2. java.util.ArrayList.SubList有实现add()、remove()方法3. 遍历集合时对元素重新赋值、对元素中的属性赋值、删除元素、新增元素3.1 普通for循环3.2 增强for循环3.3 forEach循环3.4 str…

Qt(二):使用udp发送与接收图片

使用Qt来通过UDP协议发送和接收图片可以分为几个步骤。以下是一个基本的指南&#xff1a; 发送图片准备图片数据&#xff1a;首先&#xff0c;你需要将图片转换为可以在网络上传输的数据格式。通常&#xff0c;这涉及到将图片转换为字节数组。设置UDP套接字&#xff1a;在Qt中…

Go 泛型之泛型约束

Go 泛型之泛型约束 文章目录 Go 泛型之泛型约束一、引入二、最宽松的约束&#xff1a;any三、支持比较操作的内置约束&#xff1a;comparable四、自定义约束五、类型集合&#xff08;type set&#xff09;六、简化版的约束形式七、约束的类型推断八、小结 一、引入 虽然泛型是…

水果软件2024FL Studio21.3mac苹果中文版

FL STUDIO21发布&#xff0c;提供您一直在等待的出色工作流程功能。通过新效果、多个播放列表曲目选择和无所畏惧的撤消一切编辑&#xff0c;将您的音乐带入2024年。FL Studio21中文完整版是一个功能齐全、开放式架构的PC音乐创作和制作环境。它具有基于音乐音序器的图形用户界…