数据结构第三次实验-图及其应用

这篇具有很好参考价值的文章主要介绍了数据结构第三次实验-图及其应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验目的

掌握图的存储、构建、搜索等操作和应用,能用最短路径及其搜索等算法编制较
综合性的程序,求解最优路线问题,进行程序设计、数据结构和算法设计等方面的综合训练。

二、实验内容及要求

1、任务描述
实验内容:
用户驾车出行由于出行目的的不同对道路路线选择的要求也有不同。例如,有的希望
在途中的路程尽可能短,有的则可能希望路程中时间最短。为了能满足广大旅客的需求,
编制一个城市交通咨询模拟系统,选取城市部分位置、道路抽象为程序所需要图的顶点和
边,并以城市道路长度(路程),道路的某时段的速度等信息作为图结点中的弧信息,为旅
客提供这两种最优决策的交通咨询。
输入和输出:
(1)输入形式:
构建图时,输入顶点、弧涉及的信息,包括:起始地、目的地、长度、该弧此时间
段的平均速度等信息;
用户或者客户要输入出发地和目的地,并选择何种最优决策的路线规划。
(2)输出形式:根据用户需求输出对应信息
输出最短路程所需要的路线信息和最短路程;
输出最短时间所需要的路线信息和最短时间。
实验要求:
实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。
根据输入的交通图数据,以图形化形式把交通图显示在屏幕上。
以图形化形式把最优路线显示在屏幕上。

2、能够上机编辑、调试出完整的程序。主要数据类型与变量

typedef struct
{
	int vexs[MAXVEX];
	double arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

该结构体为图的存储结构,其中vexs数组存储顶点的下标,arc数组为该图的邻接矩阵,其中的数值为权值,即路径的长度或经过该路径的平均时间。Numvertexes为图中顶点的个数,numedges为图中边的条数。

typedef int Patharc[MAXVEX];

用于存储最短路径或最小时间下标的数组。

typedef int ShortPathTable[MAXVEX];

用于存储到各点最短路径或最小时间的权值和。
3、算法或程序模块

1.void CreateMGraph(MGraph* G)

该函数用来根据输入的顶点数和边数,对图进行初始化。对vexs数组进行对应的赋值,并且对邻接矩阵除起点和终点相同的点外全部赋值为INFINITY,即65535不可达。

2.void Init(MGraph *G,MGraph *T)

该函数用来根据用户输入的信息完成相关的赋值,根据起点和终点选择对应对边,然后按照输入的长度和速度,将长度赋给图M相应的边;将时间进行计算后赋给图T相应的边,并将其输出。

3.void ShortestPath_Dijkstra(MGraph G, int v0, Patharc* P, ShortPathTable* D)

Dijkstra算法的实现,该算法的首先将各个数组进行初始化,其中final[i]=1表示顶点Vi已经加入最短路径,P[v]的值为前驱顶点下标,D[v]表示v0到v的最短路径长度和。先将V0结点加入最短路径,接着通过循环每次求得v0到其它顶点的最短路径,在循环中先将最近的结点加入到最短路径,之后根据该结点相邻的边对数组D进行修改,得到最新的V0到各顶点的最短距离。

4.Main函数

根据用户输入的起点和终点信息,通过遍历存储最短路径顶点下标的数组P依次输出对应的点,通过存储源点到各顶点最小距离的数组D中输出对应的权值。

输出最少时间路径的代码结构与上面相同,不再赘述。

三、测试

1、方案
数据结构第三次实验-图及其应用

根据该图创建对应的图结构,输入顶点的个数和边数,以及对应边的长度和通过的速度(自定)。
测试数据如下:
数据结构第三次实验-图及其应用

2、结果

数据结构第三次实验-图及其应用
数据结构第三次实验-图及其应用

数据结构第三次实验-图及其应用

可以看出最短路径与测试图中的一致,即从顶点V0到V8依次需要经过V1、V2、V4、V3、V6、V7。最少时间的实现与此相同,只是权值不同,因此也应该是正确的。

四、总结与讨论

通过本次实验我进一步掌握了图的存储结构之一——邻接矩阵存储表示,以及熟悉了Dijkstra算法执行的具体流程。
因为本次实验需要两个权值用来存储图的相关信息,因此使用邻接表的存储其实是更为合适的,对于多权值只要在其边表结点结构中添加相应的变量即可。但还是实力有限,对于邻接表的操作还不太熟练因此也未采用邻接表的存储结构。对于邻接矩阵的存储表示,两个权值究竟如何保存我先前的尝试的做法是直接在这唯一的图的结构中再添加一个二维数组。这样存储方法确实可以,但在Dijkstra算法中实现时需要对相同的流程执行两次,考虑代码冗余量太大,因此又想到了可以共用这唯一的图结构,只需将数组arc的类型更改为double,这样也兼容了int型的数据,在主函数中创建两个该图的变量G、T,将第一个图G初始化后,直接用G将T覆盖,如此也省去了对T初始化的步骤。接着将这个两个图变量的地址传入函数Init即可实现对这两个图的权值赋值工作。最后再对得到的存储图相关信息的数组进行输出即可。
对于Dijkstra这类算法,我认为最重要的还是能够掌握其思想,然后能够对代码进行灵活的运用。如果想把算法的具体代码以及细节全部掌握难度很大,同时也需要花费很多的时间,因此以后还是要尽量配合一定实操以此更好地理解其思路,及时发现自己平时学习的不足和薄弱环节,从而加以弥补。

附:程序的源代码文章来源地址https://www.toymoban.com/news/detail-460420.html

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXEDGE 20
#define MAXVEX 20
#define GRAPH_INFINITY 65535

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */

typedef struct
{
	int vexs[MAXVEX];
	double arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX];    /* 用于存储最短路径下标的数组 */
typedef int ShortPathTable[MAXVEX];/* 用于存储到各点最短路径的权值和 */
/* 构件图 */
void CreateMGraph(MGraph* G)
{
	int i, j;
	//G->numEdges = MAXEDGE;
	//G->numVertexes = MAXVEX;
	printf("请输入边数和顶点数:"); 
	scanf("%d%d", &G->numEdges,&G->numVertexes);

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		G->vexs[i] = i;
	}

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		for (j = 0; j < G->numVertexes; j++)
		{
			if (i == j)
			{
				G->arc[i][j] = 0;
			}
			
			else
			{
				G->arc[i][j] = G->arc[j][i] = GRAPH_INFINITY;
			}
			
		}
	}

	//G->arc[0][1] = 1;
	//G->arc[0][2] = 5;
	//G->arc[1][2] = 3;
	//G->arc[1][3] = 7;
	//G->arc[1][4] = 5;

	//G->arc[2][4] = 1;
	//G->arc[2][5] = 7;
	//G->arc[3][4] = 2;
	//G->arc[3][6] = 3;
	//G->arc[4][5] = 3;

	//G->arc[4][6] = 6;
	//G->arc[4][7] = 9;
	//G->arc[5][7] = 5;
	//G->arc[6][7] = 2;
	//G->arc[6][8] = 7;

	//G->arc[7][8] = 4;


	//for (i = 0; i < G->numVertexes; i++)
	//{
	//	for (j = i; j < G->numVertexes; j++)
	//	{
	//		G->arc[j][i] = G->arc[i][j];
	//	}
	//}


}
void Init(MGraph *G,MGraph *T)
{
	printf("\n请输入每条路的起点、终点、长度、速度\n(以Ctrl+Z结束输入):\n");
	int i, j, length, speed;

	while (scanf("%d %d %d %d", &i, &j, &length, &speed) != EOF)
	{//开始地,目标地,距离,速度
		G->arc[i][j] = length;
		G->arc[j][i] = length;
		T->arc[i][j] = (1.0*length) / speed;
		T->arc[i][j] = (1.0*length) / speed;
		printf("经过弧(V%d-V%d)的平均时间为:%.2f\n\n",i,j, T->arc[i][j]);
	}


}

/*  Dijkstra算法,求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度D[v] */
/*  P[v]的值为前驱顶点下标,D[v]表示v0到v的最短路径长度和 */
void ShortestPath_Dijkstra(MGraph G, int v0, Patharc* P, ShortPathTable* D)
{
	int v, w, k, min;
	int final[MAXVEX];/* final[w]=1表示求得顶点v0至vw的最短路径 */
	for (v = 0; v < G.numVertexes; v++)    /* 初始化数据 */
	{
		final[v] = 0;			/* 全部顶点初始化为未知最短路径状态 */
		(*D)[v] = G.arc[v0][v];/* 将与v0点有连线的顶点加上权值 */
		(*P)[v] = -1;				/* 初始化路径数组P为-1  */
	}

	(*D)[v0] = 0;  /* v0至v0路径为0 */
	final[v0] = 1;    /* v0至v0不需要求路径 */
	/* 开始主循环,每次求得v0到某个v顶点的最短路径 */
	for (v = 1; v < G.numVertexes; v++)
	{
		min = GRAPH_INFINITY;    /* 当前所知离v0顶点的最近距离 */
		for (w = 0; w < G.numVertexes; w++) /* 寻找离v0最近的顶点 */
		{
			if (!final[w] && (*D)[w] < min)
			{
				k = w;
				min = (*D)[w];    /* w顶点离v0顶点更近 */
			}
		}
		final[k] = 1;    /* 将目前找到的最近的顶点置为1 */
		for (w = 0; w < G.numVertexes; w++) /* 修正当前最短路径及距离 */
		{
			/* 如果经过v顶点的路径比现在这条路径的长度短的话 */
			if (!final[w] && (min + G.arc[k][w] < (*D)[w]))
			{ /*  说明找到了更短的路径,修改D[w]和P[w] */
				(*D)[w] = min + G.arc[k][w];  /* 修改当前路径长度 */
				(*P)[w] = k;
			}
		}
	}
}


int main(void)
{
	int i, j, v0,Vn;
	MGraph G,T;
	Patharc P,P2;
	ShortPathTable D,D2; /* 求某点到其余各点的最短路径 */
	v0 = 0;

	CreateMGraph(&G);
	T = G;
	Init(&G,&T);
	printf("\n请输入所查询路径的起点、终点:");
	scanf("%d%d", &v0, &Vn);

	ShortestPath_Dijkstra(G, v0, &P, &D);
	printf("最短路径如下:\n");

	printf("v%d - v%d : ", v0, Vn);
	j = Vn;
	printf("v%d<-", Vn);
	while (P[j] != -1)
	{
		printf("V%d<-", P[j]);
		j = P[j];
	}
	printf("v%d", v0);
	printf("\n");
	
	printf("\n源点到终点的最短路径长度为:\n");
	printf("v%d - v%d : %d \n", v0, G.vexs[Vn], D[Vn]);



	printf("---------------------------\n");
	ShortestPath_Dijkstra(T, v0, &P2, &D2);

	printf("最少时间如下:\n");
	printf("v%d - v%d : ", v0, Vn);
	j = Vn;
	printf("v%d<-", Vn);
	while (P2[j] != -1)
	{
		printf("V%d<-", P2[j]);
		j = P2[j];
	}
	printf("v%d", v0);
	printf("\n");

	printf("\n源点到终点的最少时间为:\n");
	printf("v%d - v%d : %d \n", v0, T.vexs[Vn], D2[Vn]);
	return 0;
}

到了这里,关于数据结构第三次实验-图及其应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】:顺序表及其通讯录应用

    1.1为什么会存在数据结构? 我们常常接触到诸如生活中的姓名、身份证、网页内的图片、视频等各种各样的信息,这些信息就是我们常说的数据。在使用这些数据时,我们发现随着数据的增加,当我们要单独寻找某一个数据时就会非常困难,就像图书馆内书籍如果没有按一定

    2024年04月26日
    浏览(39)
  • 深入理解数据结构:队列的实现及其应用场景

    队列(Queue)是一种具有先进先出(FIFO)特性的数据结构。在队列中,数据的插入和删除操作分别在队列的两端进行。插入操作在队列的尾部进行,而删除操作则在队列的头部进行。这种特性使得队列在很多实际应用中非常有用,比如任务调度、缓冲区管理等。 线性表是一种

    2024年04月28日
    浏览(51)
  • 数据结构第三遍补充(图的应用)

    Kruskal算法实现的关键是:当一条边加入到TE的集合后,如何判断是否构成回路? 答: 简单的解决方法是:定义一个一维数组Vset[n]; 存放图T中每个顶点所在的连通分量的编号。 ① 初值: Vset[i]=i, 表示每个顶点各自组成一个连通分量,连通分量的编号简单地使用顶点在图中的位置

    2024年02月06日
    浏览(47)
  • 头歌数据结构实训参考---二叉树及其应用

    第1关 实现二叉树的创建 第2关 计算二叉树的深度和节点个数 第3关 递归实现二叉树左右子树交换 第4关 非递归实现二叉树左右子树交换 第5关 层次遍历二叉树

    2024年02月05日
    浏览(41)
  • 【023】C/C++数据结构之链表及其实战应用

    💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。 👉 🎖️ CSDN实力新星,社区专家博主 👉 🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、

    2024年02月08日
    浏览(53)
  • 数据结构专题实验7——图的应用(景点管理)(C++实现)

    实验内容:应用图的技术,根据需求文件要求的功能,实现旅游景点的管理。实验要求: 使用图的数据结构建立一个景点图的结构。 可以查找各景点信息。 旅游景点导航,使用深度优先,从一个景点开始遍历所有景点。 查找一个景点到另一个景点的最短路径。 对景点道路

    2024年02月04日
    浏览(46)
  • 数据结构上机实验——栈和队列的实现、栈和队列的应用、进制转换、约瑟夫环问题

      1.利用栈的基本操作实现将任意一个十进制整数转化为R进制整数。   2.利用循环队列实现.约瑟夫环问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到k的那个人出圈;他的下一个人又从1开始报数,数到k的那个人出圈;依

    2024年02月08日
    浏览(40)
  • SQL第三次实验

    接实验2 目录 一、数据库的单表查询和连接查询 1.查询各位学生的学号、班级和姓名 2.查询课程的全部信息  3.查询数据库有哪些专业班级  4.查询学时数大于60的课程信息 5.查询在1986年出生的学生的学号、姓名和出生日期  6.查询三次作业的成绩都在80分以上的学号、课程号

    2023年04月08日
    浏览(37)
  • 【数据结构】队列及其实现

    目录 😎前言 认识队列 队列的初始化 队列判空 数据队尾入队 数据队头出队 取队头数据 取队尾数据 队列数据的个数 队列销毁 总结 上次我们学习了栈及其实现,当然也少不它的好兄弟队列啦,今天我们开始队列的学习 队列的性质是 先进先出 ,就比如车辆进出隧道一般,它

    2024年02月09日
    浏览(43)
  • 【数据结构】栈及其实现

    目录 🤠前言 什么是栈? 栈的定义及初始化 栈的定义 栈的初始化 栈的判空 栈顶压栈 栈顶出栈 栈的数据个数 栈的销毁 完整代码 总结 学了相当长一段时间的链表,总算是跨过了一个阶段。从今天开始我们将进入栈和队列的学习,相比于链表可以说是有手就行的难度,所以

    2024年02月06日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包