数据结构课设———交通查询系统设计

题目描述

今天铁路交通网络非常发达,人们在出差、旅游时,不仅关注交通费用,还关注里程和时间。请按照下图设计一个交通查询系统,能够满足旅客查询从任一个城市到另一个城市的最短里程、最低花费、最短时间、最少中转次数等问题。

[基本要求]

设计合适的数据结构和算法编写程序完成上述功能,并具有查询界面,能够按照下拉菜单选项进行选择查询。



思路

(1)这个交通查询系统实际上是带权无向图的应用。

(2)Flyod算法用于寻找图的最短路径。由于最短里程、最低花费、最短时间这三个本质上都是求最短路径,因此三者建立不同的最短路径长度矩阵和最短路径矩阵。

(3)广度遍历找到最少边数(中转次数最少)的路径。使用辅助队列,队列中最后一个城市的中转次数就是最少中转次数。广度优先遍历类似于层次遍历,当起点与终点不同层次时,使用一个变量记录遍历的层次数,找到终点时,层次数-1就是最少中转次数。

(4)界面设计,使用嵌套while循环,并且使用Sleep()函数来加强视觉效果。



代码
#include <iostream>
using namespace std;

//交通查询系统是个带权无向图

#define MaxInt 32767 //极大值
#define MVNum  100  //最大顶点数

//边信息
struct Info
{
	int length;//城市距离
	double time;//时长
	int money;//花费
};

//图定义
struct AMGraph
{
	int vexs[MVNum];//顶点表--用数字代表地名
	Info arcs[8][8];//邻接矩阵---从1开始
	int vexnum;//当前顶点数
	int arcnum;//当前边数
};

//创建一个储存城市编号和中转次数的结构体
struct note {
	int x; //城市编号1-7
	int step; //中转次数
	int pre; //前驱点在队列中的编号
};

//图操作算法
void InitG(AMGraph& G);//初始化图
void CreateG(AMGraph& G);//创建图
void Traverse(AMGraph& G);//遍历图
string OutCity(AMGraph& G, int x);//输入编号,输出城市名

//Floyd算法
void Flyod_Dis(AMGraph& G);//计算最短里程长度矩阵和最短里程长度的路径矩阵
void Flyod_Time(AMGraph& G);//计算最短时长矩阵和最短时长的路径矩阵
void Flyod_Money(AMGraph& G);//计算最少花费矩阵和最少花费的路径矩阵
void ShortDis(AMGraph& G, int x, int y);输出两地之间里程最短路径---输入两点编号
void ShortTime(AMGraph& G, int x, int y);//输出两地最短时长的路径
void ShortMoney(AMGraph& G, int x, int y);//输出两地最少花费的路径

//通过广度优先遍历得到最少中转次数
void Min_Cur(AMGraph& G, int start, int end);

//主界面
void MainSystem();
//主操作界面
void MainOperSystem();
//副操作界面
void SecondOperSystem();
//退出界面
void ExitSystem();


//初始化图
void InitG(AMGraph& G)
{
	//初始化顶点表和邻接矩阵
	for (int i = 1; i < 8; i++)
		G.vexs[i] = i;//顶点表用地址编号
	for (int i = 1; i < 8; i++)
		for (int j = 1; j < 8; j++)
		{
			G.arcs[i][j] = { MaxInt,MaxInt,MaxInt };//将矩阵的三个变量全取MaxInt
		}
}

void CreateG(AMGraph& G)
{
	InitG(G);//初始化图
	G.arcs[1][2] = { 2553,8,885 };//北京1->西安2
	G.arcs[1][3] = { 695,2.3,202 };//北京1->郑州3
	G.arcs[1][4] = { 704,2.5,225 };//北京1->徐州4
	G.arcs[2][1] = { 2553,8,885 };//西安2->北京1
	G.arcs[2][3] = { 511,1.5,148 };//西安2->郑州3
	G.arcs[2][5] = { 812,3,283 };//西安2->成都5
	G.arcs[3][1] = { 695,2.3,202 };//郑州3->北京1
	G.arcs[3][2] = { 511,1.5,148 };//郑州3-》西安
	G.arcs[3][4] = { 349,1.2,112 };//郑州3-》徐州4
	G.arcs[3][6] = { 1579,5,495 };//郑州3-》广州6
	G.arcs[4][1]= { 704,2.5,225 };//徐州4-》北京1
	G.arcs[4][3] = { 349,1.2,112 };//徐州4-》郑州3
	G.arcs[4][7] = { 651,2,162 };//徐州4-》上海7
	G.arcs[5][2] = { 812,3,283 };//成都5-》西安2
	G.arcs[5][6] = { 2358,7,684 };//成都5-》广州6
	G.arcs[6][3] = { 1579,5,495 };//广州6-》郑州3
	G.arcs[6][5] = { 2368,7,684 };//广州6-》成都5
	G.arcs[6][7] = { 1385,4,386 };//广州6-》上海7
	G.arcs[7][4] = { 651,2,162 };//上海7-》徐州4
	G.arcs[7][6] = { 1385,4,386 };//上海7-》广州6
}

void Traverse(AMGraph& G)
{
	for(int i=1;i<8;i++)
	{ 
		cout << G.vexs[i] << endl;
		for (int j = 1; j < 8; j++)
		{
			if (G.arcs[i][j].length == MaxInt)//若与城市j无连接
				continue;//跳过本次循环,直接下一次循环
			cout  <<"到"<<G.vexs[j]<<" : " << G.arcs[i][j].length << "公里   " << G.arcs[i][j].money
				<<"元   " << G.arcs[i][j].time<<"h\n";
		}
	}
}

//输入编号,输出城市名
string OutCity(AMGraph& G, int x)
{
	
	switch(x)
	{
	case 1:
		return "北京";
	case 2:
		return "西安";
	case 3:
		return  "郑州";
	case 4:
		return "徐州";
	case 5:
		return "成都";
	case 6:
		return "广州";
	case 7:
		return "上海";
	default:
		break;
	}
}

//---Floyd算法---
//思路:
//(1)先将最短路径长度矩阵初始化为该图的邻接矩阵,同时最短路径矩阵初始化为直接路径
//(2)注意考察每个点,是否有非直接路径经过该点,且导致经过该点后路径长度变短。若有,则更新最短路径和最短路径长度
//(3)最后得到最短路径矩阵和最短路径长度矩阵
//在这里一条路有里程、花费、时间、最少中转次数,因此需要建立多种矩阵


//1.计算两地最短里程
int Dis[MVNum][MVNum];//最短里程长度矩阵
int Path_Dis[MVNum][MVNum];//最短里程长度的路径矩阵

//Flyod计算最短里程长度矩阵和最短里程长度的路径矩阵
void  Flyod_Dis(AMGraph& G)
{
	//初始化两个矩阵
	for(int i=1;i<8;i++)
		for (int j = 1; j < 8; j++)
		{
			Dis[i][j] = G.arcs[i][j].length;
			if (i != j && G.arcs[i][j].length != MaxInt)
				Path_Dis[i][j] = i;//顶点i到j之间有边
			else
				Path_Dis[i][j] = -1;//无边
		}
	for (int k = 1; k < 8; k++)//逐一考察每个顶点
	{
		for(int i=1;i<8;i++)
			for(int j=1;j<8;j++)
				if (Dis[i][j] > Dis[i][k] + Dis[k][j])//若经过该点导致路径长度变短
				{
					Dis[i][j] = Dis[i][k] + Dis[k][j];//修改最短路径长度
					Path_Dis[i][j] = Path_Dis[k][j];//修改最短路径
				}
	}
}

//输出两地之间里程最短路径---输入两点编号
void ShortDis(AMGraph& G, int x, int y)
{
	int apath[MVNum] = { 0 }, d = 0;//存放一条最短路径的中间顶点(反向)及其顶点个数
	if (Dis[x][y] != MaxInt && x != y)//若顶点x和y之间存在路径
	{
		cout << "\n从" << OutCity(G, x) << "到" << OutCity(G, y) << "的最短里程路径为:  ";
		int k = Path_Dis[x][y];
		apath[d] = y;//路径上添加终点
		while (k != x)//循环添加中间点
		{
			d++;
			apath[d] = k;
			k = Path_Dis[x][k];
		}
		d++;
		apath[d] = x;//添加起点
		cout << OutCity(G, apath[d]);//输出起点
		for (int s = d - 1; s >= 0; s--)
			cout << "-->" << OutCity(G,apath[s]);
		cout << "\n\n路径最短里程:" << Dis[x][y] << endl << endl;
	}
}

//2.计算两地最短时长
double Time[MVNum][MVNum];//最短时长矩阵
int Path_Time[MVNum][MVNum];//最短时长的路径矩阵

//计算最短时长矩阵和最短时长的路径矩阵
void Flyod_Time(AMGraph& G)
{
	//初始化两个矩阵
	for (int i = 1; i < 8; i++)
		for (int j = 1; j < 8; j++)
		{
			Time[i][j] = G.arcs[i][j].time;
			if (i != j && G.arcs[i][j].time != MaxInt)
				Path_Time[i][j] = i;//顶点i到j之间有边
			else
				Path_Time[i][j] = -1;//无边
		}
	for (int k = 1; k < 8; k++)//逐一考察每个顶点
	{
		for (int i = 1; i < 8; i++)
			for (int j = 1; j < 8; j++)
				if (Time[i][j] > Time[i][k] + Time[k][j])//若经过该点导致路径长度变短
				{
					Time[i][j] = Time[i][k] + Time[k][j];//修改最短路径长度
					Path_Time[i][j] = Path_Time[k][j];//修改最短路径
				}
	}
}

//输出两地最短时长的路径
void ShortTime(AMGraph& G, int x, int y)
{
	int apath[MVNum] = { 0 }, d = 0;//存放一条最短路径的中间顶点(反向)及其顶点个数
	if (Time[x][y] != MaxInt && x != y)//若顶点x和y之间存在路径
	{
		cout << "\n从" << OutCity(G, x) << "到" << OutCity(G, y) << "的最短时长路径为:  ";
		int k = Path_Time[x][y];
		apath[d] = y;//路径上添加终点
		while (k != x)//循环添加中间点
		{
			d++;
			apath[d] = k;
			k = Path_Time[x][k];
		}
		d++;
		apath[d] = x;//添加起点
		cout << OutCity(G, apath[d]);//输出起点
		for (int s = d - 1; s >= 0; s--)
			cout << "-->" << OutCity(G, apath[s]);
		cout << "\n\n路径最短时长:" << Time[x][y] << endl << endl;
	}
}

//3.计算两地最少花费
int Money[MVNum][MVNum];//最少花费矩阵
int Path_Money[MVNum][MVNum];// 最少花费的路径矩阵

//计算最少花费矩阵和最少花费的路径矩阵
void Flyod_Money(AMGraph& G)
{
	//初始化两个矩阵
	for (int i = 1; i < 8; i++)
		for (int j = 1; j < 8; j++)
		{
			Money[i][j] = G.arcs[i][j].money;
			if (i != j && G.arcs[i][j].money != MaxInt)
				Path_Money[i][j] = i;//顶点i到j之间有边
			else
				Path_Money[i][j] = -1;//无边
		}
	for (int k = 1; k < 8; k++)//逐一考察每个顶点
	{
		for (int i = 1; i < 8; i++)
			for (int j = 1; j < 8; j++)
				if (Money[i][j] > Money[i][k] + Money[k][j])//若经过该点导致路径长度变短
				{
					Money[i][j] = Money[i][k] + Money[k][j];//修改最短路径长度
					Path_Money[i][j] = Path_Money[k][j];//修改最短路径
				}
	}
}

//输出两地最少花费的路径
void ShortMoney(AMGraph& G, int x, int y)
{
	int apath[MVNum] = { 0 }, d = 0;//存放一条最短路径的中间顶点(反向)及其顶点个数
	if (Money[x][y] != MaxInt && x != y)//若顶点x和y之间存在路径
	{
		cout << "\n从" << OutCity(G, x) << "到" << OutCity(G, y) << "的最少花费路径为:  ";
		int k = Path_Money[x][y];
		apath[d] = y;//路径上添加终点
		while (k != x)//循环添加中间点
		{
			d++;
			apath[d] = k;
			k = Path_Money[x][k];
		}
		d++;
		apath[d] = x;//添加起点
		cout << OutCity(G, apath[d]);//输出起点
		for (int s = d - 1; s >= 0; s--)
			cout << "-->" << OutCity(G, apath[s]);
		cout << "\n\n路径最少花费:" << Money[x][y] << endl<<endl;
	}
}

//通过广度优先遍历得到最少中转次数------循环每一层,若找到终点则停止
void Min_Cur(AMGraph& G, int start, int end) 
{
	if (start == end) {
		cout << "\n不需中转" << endl;
		return;
	}
	note* que = new note[10]; //简易队列,用于进行广度优先遍历
	int book[10] = { 0 }; //标记数组
	int head = 0, tail = 0; //队头队尾初始化
	int cur = 0; //临时变量
	int flag = 0; //是否到达目标城市
	//从start号城市出发,将start加入队列
	que[tail].x = start;
	que[tail].step = 0; //步数为0
	que[tail].pre = -1; //队列头的前驱顶点为-1
	tail++;
	book[start] = 1; //标记start号城市已存在队列中 
	//当队列不为空时进行循环
	while (head < tail) {
		cur = que[head].x; //当前队列中队首的城市编号
		for (int i = 1; i < 8; i++) {
			//从城市cur到城市i是否有班次并且判断i是否已经在队列中
			if ( G.arcs[cur][i].length!= MaxInt && book[i] == 0) {
				que[tail].x = i;//入队
				que[tail].step = que[head].step + 1; //中转次数+1,步数是父亲步数+1
				que[tail].pre = head; //由哪个点扩展出来的,谁就是它的父顶点
				tail++;//队尾指针后移
				book[i] = 1;//标记
			}
			//如果到达目标城市,停止扩展,退出循环
			if (que[tail - 1].x == end) {
				flag = 1;
				break;
			}
		}
		if (flag) {
			break;
		}
		head++; //队首出队
	}
	//队列中最后一个城市的中转次数就是最少中转次数
	cout << endl<<OutCity(G,start) << "-->" << OutCity(G, end) << "的最少中转次数为:" << que[tail - 1].step - 1 << "次" << endl;
	int rear = tail - 1;
	cout << "\n中转路线可以为:  " ;
	int* city = new int[8];
	int num = 0;
	for (int i = 0; i < 8; i++)
		city[i] = 0;
	while (true) {
		//如果没有达到队首,即起点城市
		if (que[rear].pre != -1)
		{
			city[num] = que[rear].x;
			num++;
		}
		else {
			city[num] = que[rear].x;
			break;
		}
		rear = que[rear].pre;
	}
	cout << OutCity(G, city[num]);
	do {
		num--;
		cout << "-->" << OutCity(G, city[num]);
	} while (city[num] != end);
	cout << endl << endl;
	delete[]que;
	delete[]city;
}


#include <windows.h>
//主界面
void MainSystem()
{
	cout << "            ************************************************************************\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "                *****||--------------**********************--------------||*****\n";
	cout << "                  ***||--------------*欢迎使用交通查询系统*--------------||***\n";
	cout << "                *****||--------------**********************--------------||*****\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "            *********||**************************************************||*********\n";
	cout << "                     ||       Loading:";
	for (int i = 0; i < 6; i++)
	{
		Sleep(500);
		cout << "  。 ";
	}
	cout << "     ||\n" << "                      ||                                                  ||\n";
}

//主操作界面
void MainOperSystem()
{
	cout << "            ************************************************************************\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "                *****||-----****************************************-----||*****\n";
	cout << "                  ***||-----*请输入你需要查询的起点和终点的城市序号*-----||***\n";
	cout << "                *****||-----****************************************-----||*****\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "            *********||**************************************************||*********\n";
	cout << "                     ||                  1. 北京                         ||\n";
	cout << "                     ||                  2. 西安                         ||\n";
	cout << "                     ||                  3. 郑州                         ||\n";
	cout << "                     ||                  4. 徐州                         ||\n";
	cout << "                     ||                  5. 成都                         ||\n";
	cout << "                     ||                  6. 广州                         ||\n";
	cout << "                     ||                  7. 上海                         ||\n";
	cout << "                     ||                  0. 退出                         ||\n";
	cout << "                     ||                                                  ||\n";
}

//副操作界面
void SecondOperSystem()
{
	cout << "            ************************************************************************\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "                *****||-----------****************************-----------||*****\n";
	cout << "                  ***||-----------*请输入你需要进行的查询操作*-----------||***\n";
	cout << "                *****||-----------****************************-----------||*****\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "            *********||**************************************************||*********\n";
	cout << "                     ||                  1. 最短里程                     ||\n";
	cout << "                     ||                  2. 最低花费                     ||\n";
	cout << "                     ||                  3. 最短时间                     ||\n";
	cout << "                     ||                  4. 最少中转次数                 ||\n";
	cout << "                     ||                  0. 退出                         ||\n";
	cout << "                     ||                                                  ||\n";
}

//退出界面
void ExitSystem()
{
	cout << "            ************************************************************************\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "                *****||-----------****************************-----------||*****\n";
	cout << "                  ***||-----------*******感谢您的使用!*******-----------||***\n";
	cout << "                *****||-----------****************************-----------||*****\n";
	cout << "              *******||--------------------------------------------------||*******\n";
	cout << "            *********||**************************************************||*********\n";
	cout << "                     ||¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥-¥||\n";

}

int main()
{
	AMGraph G;
	InitG(G);
	CreateG(G);
	int city1,city2;//输入城市的选择
	int choice;//查询操作
	MainSystem();
	while (true)
	{
		system("cls");
		MainOperSystem();;  //主操作界面显示
		cin >> city1 >> city2;
		if (city1 == 0 && city2 == 0)
		{
			system("cls");
			ExitSystem();
			Sleep(1000);
			break;
		}
		if (city1 > 0 && city1 < 8 && city2>0 && city2 < 8&&city1!=city2)
		{
			system("cls");//清空界面
			while (true)
			{
				SecondOperSystem();
				cin >> choice;
				if (choice == 0)   //退出副界面
					break;
				switch (choice)
				{
				case 1:   //最短里程
					Flyod_Dis(G);
					ShortDis(G, city1, city2);//输出最短里程路径
					system("pause");
					system("cls");
					break;
				case 2:   //最低花费  
					Flyod_Money(G);
					ShortMoney(G, city1, city2);
					system("pause");
					system("cls");
					break;
				case 3:   //最短时间 
					Flyod_Time(G);
					ShortTime(G, city1, city2);
					system("pause");
					system("cls");
					break;
				case 4:   //
					Min_Cur(G, city1, city2);
					system("pause");
					system("cls");
					break;
				default:
					cout << "输入错误!" << endl;
					system("pause");
					system("cls");
					break;
				}
			}
		}
		else {
			cout << "输入有误,请重新输入!\n";
			system("pause");
		}
	}
}


运行结果

初始界面

主操作界面

副操作界面

退出界面

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值