基于Dijkstra的校园导游系统

目录

一. 设计目的

二. 设计背景

三. 系统功能

四. 系统算法实现

五. 系统调试与结果分析

六. 完整源代码


一. 设计目的

        通过设计并实现校园导游系统,使学生对数据结构有更深入的了解。该系统综合性非常广,能够极大提高学生的设计,编程及调试等解决实际应用的能力。培养对实际问题的分析,建模等逻辑思维。

二. 设计背景

        随着校园规模的扩大,游客和学生对校园内景点信息的需求日益增加。传统的纸质地图已难以满足其需求,因此开发一款校园导游系统显得尤为重要。本系统以湖南城市学院为例,实现了基于Dijkstra算法的最短路径查询功能,以及景点信息查询和推荐等功能。

三. 系统功能

        1)地图展示功能:首先系统能够展示校园景点的大致分布图,帮助用户直观了解校园布局。知道校园有哪些景点可以前往。

        2)推荐景点模块:在查看了整个校园大致分布图后,如果用户不知道该前往何处,就可以查看推荐景点,前往合适自己前往的景点。

        3)景点信息查询模块:用户若在地图上不熟悉景点的信息以及作用,就可以输入景点编号,查看景点的所有信息简介。

        4)景点间最短路径的查询:当用户已经明确了自己想要前往的景点,就可以输入用户当前所在位置以及想要前往的景点,系统就会给出到达目标景点的最短路径,切实帮助用户快速到达目的地。

        

四. 系统算法实现

        系统在查询景点间最短路径当中,就使用了Dijkstra算法。该算法主要用于计算图中一个顶点到其他所有顶点的最短路径。算法核心是通过不断选取未访问的顶点中距离起点最近的顶点,并更新其相邻顶点的距离,直到所有顶点都被访问过。

        实现该算法主要使用如下四个函数:

        Create函数用来初始化校园景点图,包括设置顶点数、边数、初始化邻接矩阵、输入景点信息及道路信息等。

        inquire函数:根据用户输入的景点编号,输出该景点的详细信息。

        Dijkstra函数:实现Dijkstra算法,计算并输出从起点到终点的最短路径及长度。

        PrintPath函数:辅助函数,用于打印从起点到终点的最短路径。

五. 系统调试与结果分析

         

首先用户会看到这样的一个交互界面,这是文本形式的交互界面,所以这个可以作为我们这个系统的改进,未来可以考虑增加图形用户界面(GUI),提高用户体验。

接着,我们可以查看整个学校的平面图,输入操作1:

只要我们的用户没有执行退出操作,就可以一直使用校园导游系统。

假设我们用户此时在编号为1,也就是学校北门的位置,想要前往学校图书馆,也就是编号为5的景点,想要知道前往图书馆的最短路径,方便她快速到达,就可以执行第4个操作,如下所示:

 

系统就会给出最短路径长度,以及最短路径,也就是从学校北门先经过篮球场,最后到达图书馆,就是最短的路径。

用户如不需要再使用该系统就可以执行第5步操作,退出我们的校园导游系统,如下所示:

 

六. 完整源代码
//基于Dijkstra的校园导游系统。
//这里我们以湖南城市学院大学的部分景点为例
#include<stdio.h>
#include<string.h>
#include<limits.h>;
//首先确定一个景点所包含的内容:景点名称,景点简介
#define MAXSIZE 100		//定义一个数组最大值
typedef struct ElemType {
	int id;				//为了方便管理,设置一个顶点编号
	char name[MAXSIZE];		//景点名称,用一个字符数组存储
	char introduce[MAXSIZE];	//景点的简介,也用字符数组存储起来
}ElemType;

//构建一个图,使用邻接矩阵来存储
typedef struct Graph {
	ElemType vexs[MAXSIZE];		//存放顶点
	int arcs[MAXSIZE][MAXSIZE];	//邻接矩阵
	int vexnum,arcnum ;		//顶点数和边数
}Graph;

//函数声明
void map();
void choice();
void recommend();
Graph Creat(Graph& G);
void inquire(Graph G, int n);
void PrintPath(Graph G, int prev[], int start, int end);
void Dijkstra(Graph& G, int start,int end);

int main()
{
	Graph G=Creat(G);	//创建一个图,并对这个图进行相应的初始化和信息录入
	
	while (1) {
		int num;
		int num1;	//用来接收第二个操作的景点编号
		printf("\n");
		choice();	//菜单界面
		scanf("%d", &num);
		switch (num) {		//使用一个switch语句来处理用户所要进行的操作
		case 1:map(); break;	//break使这个switch语句结束
		case 2:printf("请输入要查询的景点编号(1~10):\n");
			scanf("%d", &num1);
			inquire(G, num1);
			break;
		case 3:recommend(); break;
		case 4:printf("请输入您现在所在景点的编号,以及想要去的景点编号:\n");
			int start, end;
			scanf("%d %d", &start, &end);
		    Dijkstra(G,start,end);
			break;
		case 5:printf("感谢使用本校导游系统,欢迎下次再来");
			return 0;	//整个函数结束
		default:printf("请输入正确的操作指令");
			break;
		}
	}

}


//首先创立一个函数来展示学校平面图
void map() {
	//打印出学校景点的大概方位
	printf("\n");
	printf("--------------------\n");
	printf("·····1·····\n");
	printf("2···· 3·····\n");
	printf("··4·· 5···6  7\n");
	printf("··8········\n");
	printf("9···· 10·····\n");
	printf("---------------------\n");
	printf("地图备注:1--学校北门   2--老食堂   3--篮球场\n");
	printf("4--操场  5--图书馆   6--教学楼1  7--教学楼2\n");
	printf("8--新食堂  9--宿舍楼  10--学校南门\n");
}

//接着创建一个菜单供用户选择
void choice() {
	printf("********欢迎来到湖南城市学院********\n");
	printf("------------------------------------\n");
	printf("****** 1.湖南城市学院整体平面图 ****\n");
	printf("****** 2.查询所有景点信息           ****\n");
	printf("****** 3.查看推荐前往景点       ****\n");
	printf("****** 4.查询到达景点的最短路径 ****\n");
	printf("****** 5.退出                   ****\n");
	printf("------------------------------------\n");
	printf("请输入您想要进行的操作:\n");
}

//构造一个提供推荐景点的函数
void recommend() {
	printf("老食堂推荐指数:*****\n");
	printf("老食堂一楼二楼都有许多特色美食,有些菜品,口感鲜美,让人陶醉;有些佳肴,香气扑鼻,让人无法自拔。\n");
	printf("在品完美食后,还能去一楼蜜雪冰城,益禾堂,瑞幸咖啡等知名品牌店去挑选一杯下午茶,可谓是快活似神仙啊\n");
	printf("吃饱喝足才有力气,热爱美食的朋友们可千万不要错过哦\n");
	printf("\n");
	printf("学校图书馆推荐指数: ****\n");
	printf("学校图书馆收藏着大量图书,各种各样的图书应有尽有。丰富的阅读让思想的翅膀翱翔,让你轻松漫步在知识的丛林,开启智慧的翅膀\n");
	printf("向着本就属于你的高度往上攀登,终能站在巅峰");
	printf("丰富的物质固然重要,但丰富的精神内涵也缺一不可\n");
	
}

//开始录入景点信息
Graph Creat(Graph& G) {
	G.vexnum = 10;	//已知景点总数为10
	G.arcnum = 19;	
	//从1到10给景点编号
	for (int i = 1; i <= G.vexnum; i++) {
		G.vexs[i].id = i;
	}

	//开始初始化道路
	for (int j = 1; j <= G.vexnum; j++) {
		for (int k = 1; k <= G.vexnum; k++) {
			G.arcs[j][k] = INT_MAX;
		}
	}

	//开始根据实际情况输入有道路的两个顶点
	G.arcs[1][2] = G.arcs[2][1] = 300;	//道路是互通,能从一个景点到另外一个景点,也能从另外一个景点到这个景点
	G.arcs[1][3] = G.arcs[3][1] = 100;

	G.arcs[2][3] = G.arcs[3][2] = 150;
	G.arcs[2][4] = G.arcs[4][2] = 160;
	G.arcs[2][8] = G.arcs[8][2] = 310;
	G.arcs[2][9] = G.arcs[9][2] = 350;

	G.arcs[3][5] = G.arcs[5][3] = 110;
	G.arcs[3][6] = G.arcs[6][3] = 250;

	G.arcs[4][8] = G.arcs[8][4] = 170;
	G.arcs[4][9] = G.arcs[9][4] = 260;

	G.arcs[5][6] = G.arcs[6][5] = 180;
	G.arcs[5][10] = G.arcs[10][5] = 270;
	G.arcs[5][8] = G.arcs[8][5] = 280;

	G.arcs[6][10] = G.arcs[10][6] = 320;
	G.arcs[6][7] = G.arcs[7][6] = 120;

	G.arcs[7][10] = G.arcs[10][7] = 330;

	G.arcs[8][9] = G.arcs[9][8] = 190;
	G.arcs[8][10] = G.arcs[10][8] = 200;

	G.arcs[9][10] = G.arcs[10][9] = 210;

	//开始输入景点的名称和简介
	strcpy(G.vexs[1].name, "学校北门");
	strcpy(G.vexs[1].introduce,"一个供学生自由出入的大门,北门外面有着学校周边数量最多的美食摊位。");
	strcpy(G.vexs[2].name,"老食堂");
	strcpy(G.vexs[2].introduce,"窗口众多,饭菜可口,是舌尖上的美味");
	strcpy(G.vexs[3].name,"篮球场");
	strcpy(G.vexs[3].introduce,"强身健体,增进友谊,挥发汗水的宝地");
	strcpy(G.vexs[4].name,"操场");
	strcpy(G.vexs[4].introduce,"每晚都不缺夜跑的人,有许多社团活动也在这个操场举行");
	strcpy(G.vexs[5].name,"图书馆");
	strcpy(G.vexs[5].introduce,"一座充满学习氛围的殿堂,里面的每一位学生都在诠释着努力上进的姿态");
	strcpy(G.vexs[6].name,"教学楼1");
	strcpy(G.vexs[6].introduce,"平日里学生们经常上课的地方,里面布满了桌椅");
	strcpy(G.vexs[7].name,"教学楼2");
	strcpy(G.vexs[7].introduce,"学生们上课的第二场所");
	strcpy(G.vexs[8].name,"新食堂");
	strcpy(G.vexs[8].introduce,"里面大多是新开的窗口,是吃腻了老食堂的第二选择");
	strcpy(G.vexs[9].name,"宿舍楼");
	strcpy(G.vexs[9].introduce,"我们大家都需要一个港湾,而宿舍就是我们在学校的港湾,用来放松休息");
	strcpy(G.vexs[10].name,"学校南门");
	strcpy(G.vexs[10].introduce,"学校与北门遥遥相对的一道门");

	//在完成上述初始化,以及信息录入之后,返回这个图
	return G;
}

//创建一个函数用来输出一个景点的信息
void inquire(Graph G, int n) {
	if (n < 1 || n>10)
		printf("输入的景点编号有误(请输入1~10的景点编号)\n");
	else {
		printf("编号为%d的景点信息如下所示:\n", G.vexs[n].id);
		printf("该景点名称为%s\n", G.vexs[n].name);
		printf("该景点的简介:%s\n", G.vexs[n].introduce);
	}
}

//辅助函数,用来打印从start到end的路径
void PrintPath(Graph G,int prev[], int start, int end) {
	if (end == start) {		
		printf("%s", G.vexs[end].name);
		return;
	}
	PrintPath(G,prev, start, prev[end]);	//递归调用这个算法,直到把所有路径都打印出来
	printf("-> %s", G.vexs[end].name);
}

//创建一个函数来求得任意两个顶点间的最短路径
void Dijkstra(Graph& G, int start, int end) {
	int dist[MAXSIZE];	//用来存放初始顶点到其他所有顶点的距离
	int visited[MAXSIZE];	//用来存放这个顶点是否被访问过
	int prev[MAXSIZE];	//用来存放前驱顶点

	//初始化距离和前驱结点
	for (int i = 1; i <= G.vexnum; i++) {
		dist[i] = INT_MAX;	
		visited[i] = 0;
		prev[i] = -1;
	}

	dist[start] = 0;	//起始顶点到自身距离为0

	//开始遍历所有顶点
	for (int count = 0; count < G.vexnum - 1; count++) {
		int u = -1;

		//找出未访问的顶点中距离最小的顶点
		for (int i = 1; i <= G.vexnum; i++) {
			if (!visited[i] && (u == -1 || dist[i] < dist[u])) {
				u = i;
			}
		}

		visited[u] = 1;		//表示这个顶点已经被访问过

		//更新相邻顶点的距离和前驱结点
		for (int j = 1; j <= G.vexnum; j++) {	//通过判断新加了一个顶点后,能不能通过这个顶点使原来的距离更近,这是算法核心
			if (!visited[j] && G.arcs[u][j] != INT_MAX && dist[u] != INT_MAX && dist[u] + G.arcs[u][j] < dist[j]) {
				dist[j] = dist[u] + G.arcs[u][j];
				prev[j] = u;
			}
		}
	}
	//检查是否存在路径
	if (dist[end] == INT_MAX) {
		printf("从%s 到 %s 不存在路径\n", G.vexs[start].name, G.vexs[end].name);
	}
	else {
		printf("从%s 到 %s 的最短路径长度为%d,路径为:", G.vexs[start].name, G.vexs[end].name, dist[end]);
		PrintPath(G,prev, start, end);
		printf("\n");
	}
}

 

        

  • 37
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值