【数据结构C语言版】课程实验-图的应用

数据结构C语言版 - 图的应用

前言:

大二本科计算机科学与技术程序员一枚,总结几篇课后实验内容,希望可以帮助到大家。 软件:Devc++

实验目的:

通过实验掌握图的基本存储原理,能够利用图模型存储数据并实现对图的两点间的最短路径的求取过程,巩固所学的基本概念和方法,掌握必要的图模型数据结构的程序设计技术。
(1)熟练掌握图的邻接矩阵与邻接表存储结构及其应用;
(2)能设计出基于两种存储方法的应用程序;
(3)理解并掌握最短路径算法的基本思想及其算法方法的实际应用。


实验内容:

构建一个校园交通查询系统程序。能够规划出任意出发地和目的地之间的最短路径。

实验步骤:

(1)将校园中的重要地点(如教学楼、宿舍楼、餐厅、图书馆等主要地点位置以及主要的道路和路口等联系起来并绘制草图,然后将其抽象为图中的结点(序号)、边,道路中各相邻结点间的近似距离作为边上的权值,形成图结构);
(2)对上述图结构采用邻接矩阵方法进行存储,图中结点的实际名称和图序号之间的对应关系可以另外通过建立一个一维数组对应存储(名称和序号能够实现相互转换);
(3)交通查询:输入一个图中起点位置名称(可由程序转换为结点序号)以及要到达的目的地位置名称(可转换为结点序号),就可通过Floyd算法规划出该两点间的一条最短路径并输出该路径中间所经过的主要位置(结点)的名称序列以及该路径的距离。


实验难点:

本实验的难点在于两点:
1.图的邻接矩阵的建立,有两张方式,一种是通过键盘输入相关地点和权值建立,另一种是通过读取文本文件的方式建立。我采用的是后者。
2.Floyd算法的输出。


实验过程

先看一下程序要的结果图:
程序运行的结果

建立图的邻接矩阵

先看一下通过读取文本内容的txt文件的存放路径以及内容。
图的建立
这个txt文本文件一定要放到当前源文件的目录下,具体代码后面会讲到。
txt文本内容说明
6 8 : 要建立的图共有6个顶点和8条边

各个序号后面跟着的地点名称为 每个顶点代表的地点名称,因为题目要求实现结点序号和地点名称相互转化,我采用了这种方式,当然,你也可以在代码中自己创建一个一维数组进行保存。

0 1 50 : 代表0号结点到1号结点的权值为50
ctrl+S保存后我们的txt文件就可以放到那里不用动了

                                     ==接下来上代码==

需要用到的头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <conio.h>
#include <Windows.h>

常量定义

#define M 100   //图最大的结点数目
#define INFINITY 100000  //无穷

typedef int EdgeType;
typedef int Distance[M][M];   /* 距离向量类型*/
typedef int Path[M][M];   /* 路径类型*/

用到的结构体

typedef struct {
	char name[20];               //学校地名的名称
	int id;                      //地名的编号
}VextexType;

typedef struct{
	VextexType vertex[M];    //结点信息
	EdgeType arc[M][M]; //图的边的信息
	int n, e;    //图的结点数和边数
}MGraph;

函数声明

void  Menu(); //主界面函数
void Create(MGraph *G); //用读取文件的方式建立图的邻接矩阵
int NameId(MGraph G, char *loc); //通过学校地点名称查找景点的编号
void Floyd(MGraph G, char *loc1, char *loc2, Path path, Distance distance); //Floyd算法
void PrintPath(int u, int v, int path[][M], MGraph G, Distance d); //输出最短路径所经过的结点以及最短距离
void printnum(MGraph *G); //输出编号以及地点名称
void printSchool(MGraph *G); //输出学校地点的图邻接矩阵
void Exit(); //退出程序

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <conio.h>
#include <Windows.h>

#define M 100   //图最大的结点数目
#define INFINITY 100000  //无穷

typedef int EdgeType;
typedef int Distance[M][M];   /* 距离向量类型*/
typedef int Path[M][M];   /* 路径类型*/

typedef struct {
	char name[20];               //学校地名的名称
	int id;                      //地名的编号
}VextexType;

typedef struct{
	VextexType vertex[M];    //结点信息
	EdgeType arc[M][M]; //图的边的信息
	int n, e;    //图的结点数和边数
}MGraph;
/*主界面函数*/
void Menu(){
	printf("\n\n\t\t\t 欢迎使用中北大学信息商务学院校园导游系统");
	printf("\n\t\t\t*******************************************\n\n\n");
	printf("\t\t\t\t请选择您需要的功能\n\n");
	printf("\t\t\t\t1.查询两个点之间的最短路径(Floyd)\n\n");
	printf("\t\t\t\t2.输出编号以及地点名称\n\n");
	printf("\t\t\t\t3.输出学校地图的邻接矩阵(无向图)\n\n");
	printf("\t\t\t\t4.退出程序\n");
	printf("\n\n\t\t\t*******************************************\n\n");
}
/*用读取文件的方式来建立图的邻接矩阵*/
void Create(MGraph *G){
	int i, j, k, w;

	FILE *rf;
	rf = fopen("D:\\Devc++Work\\Graph\\g1.txt", "r"); //这里的路径为txt文本的路径
	if (!rf){
		printf("error!");
		return;
	}
	if (rf)
	{
		fscanf(rf, "%d%d", &G->n, &G->e);
		for (i = 0; i<G->n; i++)
		{
			fscanf(rf, "%d%s", &G->vertex[i].id, G->vertex[i].name);
		}

		for (i = 0; i<G->n; i++)
		{
			for (j = 0; j<G->n; j++)
			{
				if (i == j) G->arc[i][j] = 0;
				else G->arc[i][j] = INFINITY;
			}
		}
		for (k = 0; k<G->e; k++)
		{
			fscanf(rf, "%d%d%d", &i, &j, &w);
			G->arc[i][j] = w;
			G->arc[j][i] = w;
		}
		fclose(rf);
	}
	else G->e = 0;
}
/*通过学校地点名称查找景点的编号*/
int NameId(MGraph G, char *loc) {
	int i;
	int flag = -1;
	for (i = 0; i < G.n; i++) {
		if (strcmp(G.vertex[i].name, loc) == 0) {
			flag = i;
			break;
		}
	}

	return flag;
}

/*Floyd算法*/
void Floyd(MGraph G, char *loc1, char *loc2, Path path, Distance distance){
	int l1, l2;

	l1 = NameId(G, loc1);
	l2 = NameId(G, loc2);

	int i, j, k;
	//初始化distance数组和path数组
	for (i = 0; i < G.n; i++) {
		for (j = 0; j < G.n; j++) {
			distance[i][j] = G.arc[i][j];
			path[i][j] = -1;

		}
	}
	//三层循环,寻找最短路径
	for (k = 0; k < G.n; k++){ //这层代表中间点
		for (int i = 0; i < G.n; i++) {
			for (int j = 0; j < G.n; j++) {
				if (distance[i][j] > distance[i][k] + distance[k][j]) {
					distance[i][j] = distance[i][k] + distance[k][j]; //顶点之间的距离
					path[i][j] = k;
				}
			}
		}
	}
}
/*输出最短路径所经过的结点以及最短距离*/
void PrintPath(int u, int v, int path[][M], MGraph G, Distance d) {
	int mid;
	
	if (path[u][v] == -1) {
		//直接输出,没有中间点
		printf("<%s,%s>", G.vertex[u].name, G.vertex[v].name);
	}
	else { //有中间点
		mid = path[u][v];
		PrintPath(u, mid, path,G,d);
		PrintPath(mid, v, path,G,d);
	}
}
//输出编号以及地点名称
void printnum(MGraph *G)
{
	int i = 0;
	printf("\n");
	for (i = 0; i<G->n; i++)
	{
		printf("                     地点编号及名称:%d\t%s\n", G->vertex[i].id, G->vertex[i].name);
		printf("\n");
	}
}

/*输出学校地点的地图邻接矩阵*/
void printSchool(MGraph *G){
	int i, j;
	printf("                     学校地图的邻接矩阵为:\n");
	for (i = 0; i < G->n; i++)
	{
		for (j = 0; j < G->n; j++)
		{
			if (G->arc[i][j] == INFINITY)
				printf("          ∞\t");//用∞代表俩顶点之间无联系
			else
				printf("          %d\t", G->arc[i][j]);
		}
		printf("\n");
	}
}

/*退出程序的函数*/
void Exit(){
	for (int i = 2; i >= 1; i--) {
		printf("                     程序正在退出,倒计时:%d秒\n", i);
		Sleep(1000);
	}
	exit(0);
}
/*主函数入口*/
int main() {
	Path p;
	Distance d;
	MGraph G;
	Create(&G);

	while (1){
		int choice;
		char loc1[100] = { 0 };
		char loc2[100] = { 0 };

		Menu();
		printf("                     请输入你想要的的操作:");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:

			printf("                     请输入您想查找最短路径的两个地点的名称:");
			scanf(" %s %s", &loc1, &loc2);
			if (NameId(G, loc1) == -1 || NameId(G, loc2) == -1){
				printf("学校地点输入错误!\n");
			}
			else{
				Floyd(G, loc1, loc2, p, d);
				int l1 = NameId(G, loc1);
				int l2 = NameId(G, loc2);
				printf("                     %d号-%d号 最短距离为:%d米 \n", l1, l2, d[l1][l2]);
				printf("                     最短路径为:");
				PrintPath(l1,l2,p,G,d);
			}
			break;
		case 2:
			printnum(&G);
			break;
		case 3:
			printSchool(&G);
			break;
		case 4:
			Exit();
			break;

		default:
			break;
		}

	}
	return 0;
}

总结

第一次写博客,有改进的地方希望可以一起交流,热爱学习,好好生活。

  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值