公交线路提示(图)

目录

问题描述

题目内容

基本要求

问题分析

需求分析

数据结构

算法设计

源代码


问题描述

题目内容

上网下载真实南京公交线路图,建立南京主要公交线路图的存储结构。

基本要求

  1. 输入任意两站点,给出转车次数最少的乘车路线。
  2. 输入任意两站点,给出经过站点最少的乘车路线。

问题分析

需求分析

需要将公交路线文件进行处理,获取每一个站点与公交的信息,最后进行两种路线的查询。

数据结构

本题采用数据结构:图

采用该结构的原因:由于节点之间有路径,每个节点有编号,且搜索相关路径,需使用图来解决该题。

算法设计

由于两种路线都与求最短相关路径有关,故都采用迪杰斯特拉算法。

  求经过站点最少的路径:设置三个辅助数组,dist[]、path[]和visited[].其中dist[i]表示起始站点到站点i的最短距离;path[i]=j,表示从起始站点到达站点i会经过站点j;visited [i]表示顶点i的选中状态,若被选中,则下一次访问不考虑该节点。由于最少站点路径只关乎站点个数,所以每个站点距离其可到达的站点距离记作1。初始情况下,只有起始点被选中,其余顶点均是未选中状态。dist数组中记录的是起始点与其余顶点之间当前的最短路径,即起始点与其余顶点边的权值,如果不存在边,则权值为无穷大。循环遍历dist数组,每次遍历都选出dist数组中最小元素值并进行标记,随后更新其余未标记点的状态,直至能到达的顶点都被标记。

  求换乘次数最少的路径:设置五个辅助数组,dist[]、path[]、visited[]、changebus[]、pathbus[][],其中dist[i] 表示起始站点到站点i的最少换乘次数;若path[i]=j,表示从起始站点到达站点i会经过站点j;visited [i]表示顶点i的选中状态,若被选中,则下一次访问不考虑该节点;changebus[i]表示与path[i]=j相关的j节点到i节点是否需要换乘;pathbus[i][]表示与path[i]=j相关的j节点到i节点乘坐的公交车。若不需换乘dist[i]=dist[j],如需要dist[i]=dist[j]+1,其余思路与第一问相似。

源代码

Bus.h
#include <iostream>
#include <fstream>
#include <stack>
using namespace std;
#define Msize 950
#define Maxnum 0x3f3f3f3f
struct Node
{
	char name[100];
	int bus_num;
	int value;
	Node* next;
};//邻接表节点
struct Hnode
{
	char name[100];
	Node* first;
};//邻接表头节点
struct Graph
{
	Hnode H[Msize];
	int sum;
	bool M[Msize][Msize];//邻接矩阵
};//表节点
char line[1005];//文件操作辅助字符串
int dist[Msize];//起始点与其余顶点之间当前的最短路径
int path[Msize];//起始站点到达站点i会经过的站点
int ans[Msize];
bool visited[Msize];//表示顶点的选中状态
bool changebus[Msize];//表示顶点的换乘状态
int pathbus[Msize][20];//表示到达顶点的公交车
stack<int> s1;
stack<int> s2;
/**相同字符串比较函数**/
bool Str_Cmp(char* key_1, char* key_2)
{
	if (key_1 == key_2)
	{
		return true;
	}//同一个字符串
	int start = 0;
	while (key_1[start] != '\0' && key_2[start] != '\0')
	{
		if (key_1[start] != key_2[start])
		{
			break;
		}
		start++;
	}//依次比较
	if (key_1[start] == '\0' && key_2[start] == '\0')
	{
		return true;
	}
	else
	{
		return false;
	}
}
/**站点分割函数**/
bool Divid_Station(char key_1)
{
	if (key_1 == ',' || key_1 == '\0')
	{
		return true;
	}//遇到逗号产生一个站点
	return false;
}
/**字符串移植函数**/
void Str_Cpy(char* key_1, char* key_2)
{
	int start = 0;
	while (key_1[start] != '\0')
	{
		key_2[start] = key_1[start];
		start++;
	}//将key_1的内容放入key_2中
	key_2[start] = '\0';
}
/*处理站点*/
void Get_Information_From_File(char** s, int& k, Graph& G)
{
	//将每个站点分开放入station.txt中
	fstream bfile, sfile, csfile;
	bfile.open("JiangNing.txt", ios::in);
	sfile.open("station.txt", ios::out);
	if (!bfile.good() || !sfile.good())
	{
		cout << "文件打开失败" << endl;
		exit(1);
	}
	while (!bfile.eof() && bfile.peek() != EOF)
	{
		char add_station;
		bfile.getline(line, 1000);
		int start = 8;
		while (line[start] != '\0' && line[start] != '\n')
		{
			int temp_start = 0;
			char temp_char[100];
			for (int i = 0; i < 100; i++)
			{
				temp_char[i] = '\0';
			}
			while (line[start] != '\0' && line[start] != '\n' && line[start] != ' ')
			{
				add_station = line[start];
				if (!Divid_Station(add_station))
				{
					temp_char[temp_start] = line[start];
					temp_start++;
					start++;
				}
				else
				{
					start++;
					break;
				}
			}
			sfile << temp_char << endl;
		}
	}
	bfile.close();
	sfile.close();
	//将重复站点删除
	csfile.open("Fstation.txt", ios::out);
	sfile.open("station.txt", ios::in);
	if (!csfile.good() || !sfile.good())
	{
		cout << "文件打开失败" << endl;
		exit(1);
	}
	char ch[100];
	while (!sfile.eof() && sfile.peek() != EOF)
	{
		int i = 0;
		sfile.getline(ch, 95);
		for (i = 0; i < k; i++)
		{
			if (Str_Cmp(ch, s[i]))
			{
				break;
			}
		}
		if (i == k)
		{
			s[k] = (char*)malloc(sizeof(char) * 100);
			if (!s[k])
			{
				exit(1);
			}
			Str_Cpy(ch, s[k]);
			k++;
			csfile << ch << endl;
		}
	}
	csfile.close();
	sfile.close();
	fstream tfile;
	//将中文站点换成编号
	bfile.open("JiangNing.txt", ios::in);
	tfile.open("Bus_NUm.txt", ios::out);
	if (!bfile.good() || !tfile.good())
	{
		cout << "文件打开失败" << endl;
		exit(1);
	}
	while (!bfile.eof() && bfile.peek() != EOF)
	{
		char add_station;
		bfile.getline(line, 1000);
		tfile << line[0] << line[1] << line[2] << ' ';
		int start = 8;
		while (line[start] != '\0')
		{
			int temp_start = 0;
			char temp_char[100];
			for (int i = 0; i < 100; i++)
			{
				temp_char[i] = '\0';
			}
			while (line[start] != '\0' && line[start] != '\n')
			{
				add_station = line[start];
				if (!Divid_Station(add_station))
				{
					temp_char[temp_start] = line[start];
					temp_start++;
					start++;
				}
				else
				{
					start++;
					break;
				}
			}
			for (int j = 0; j < k; j++)
			{
				if (Str_Cmp(s[j], temp_char))
				{
					tfile << j + 1 << ' ';
					break;
				}
			}
		}
		tfile << endl;
	}
	bfile.close();
	tfile.close();
	//将每个站点可到达的站点存储
	fstream ctfile;
	tfile.open("Bus_Num.txt", ios::in);
	ctfile.open("Graph.txt", ios::out);
	if (!tfile.good() || !ctfile.good())
	{
		cout << "Bus_Num.txt或Graph.txt无法打开" << endl;
		exit(1);
	}
	for (int i = 1; i <= G.sum; i++)
	{
		while (!tfile.eof() || tfile.peek() != EOF)
		{
			tfile.getline(line, 1000);
			int start = 4;
			while (line[start] != '\0' && line[start] != '\n')
			{
				int temp_num = 0;
				while (line[start] != ' ' && line[start] != '\0' && line[start] != '\n')
				{
					temp_num = temp_num * 10 + (line[start] - ('0' - 0));
					start++;
				}
				start++;
				if (temp_num == i)
				{
					int temp_next = 0;
					if (line[start] != ' ' && line[start] != '\0' && line[start] != '\n')
					{
						while (line[start] != ' ' && line[start] != '\0' && line[start] != '\n')
						{
							temp_next = temp_next * 10 + (line[start] - ('0' - 0));
							start++;
						}
						ctfile << temp_next * 1000 + (line[0] - ('0' - 0)) * 100 + (line[1] - ('0' - 0)) * 10 + (line[2] - ('0' - 0)) << ' ';
					}
				}
			}
		}
		ctfile << endl;
		tfile.clear();
		tfile.seekg(0L, ios::beg);
	}
	tfile.close();
	ctfile.close();
}
/**创建图**/
void Creat_Graph(Graph& G, char** s)
{
	for (int i = 1; i <= G.sum; i++)
	{
		G.H[i].first = NULL;
	}//初始化
	fstream cfile;
	cfile.open("Graph.txt", ios::in);
	if (!cfile.good())
	{
		exit(1);
	}
	int under = 1;
	//从文件中获取信息构建图
	while (cfile.peek() != EOF && !cfile.eof())
	{
		Str_Cpy(s[under - 1], G.H[under].name);
		cfile.getline(line, 1000);
		int start = 0;
		while (line[start] != '\n' && line[start] != '\0')
		{
			int temp = 0;
			while (line[start] != '\n' && line[start] != '\0' && line[start] != ' ')
			{
				temp = temp * 10 + (line[start] - ('0' - 0));
				start++;
			}
			start++;
			int temp_s, temp_h;
			temp_s = temp / 1000;
			temp_h = temp % 1000;
			Node* p = (Node*)malloc(sizeof(Node));
			if (!p)
			{
				exit(1);
			}
			Str_Cpy(s[temp_s - 1], p->name);
			p->bus_num = temp_h;
			p->next = G.H[under].first;
			G.H[under].first = p;
			G.M[under][temp_s] = 1;//邻接矩阵构建
		}//邻接表的构建
		under++;
	}
	cfile.close();
}
/**文件中找站对应编号**/
void Check_Station(Graph& G, char* b, char* e, int& bs, int& es, char** s)
{
	//从s数组中找符合的站点名称
	for (int i = 0; i < G.sum; i++)
	{
		if (Str_Cmp(b, s[i]))
		{
			bs = i + 1;
		}
		if (Str_Cmp(e, s[i]))
		{
			es = i + 1;
		}
		if (bs && es)
		{
			break;
		}
	}
}
/**输出方案**/
void Print_Solution(char** s, Graph& G)
{
	int top, ntop;
	int temp_bus = 0;
	int i = 0;
	//将s1栈中存储的站点输出
	while (!s1.empty())
	{
		top = s1.top();
		i++;
		s1.pop();
		if (!s1.empty())
		{
			ntop = s1.top();
			Node* p = G.H[top].first;
			while (p)//遍历找到合适的公交
			{
				if (Str_Cmp(s[ntop - 1], p->name))
				{
					if (temp_bus != p->bus_num)
					{
						cout << endl;
						cout << "    (乘" << p->bus_num << "路)" << endl;
						cout << "    " << s[top - 1] << " -> " << s[ntop - 1];
						temp_bus = p->bus_num;
					}
					else
					{
						cout << " -> " << s[ntop - 1] << ' ';
					}
					break;
				}
				p = p->next;
			}
		}
	}
	cout << endl;
	cout << endl;
	cout << "    *共经过" << i << "站*" << endl;
	cout << endl;
	cout << endl;
}
/**迪杰斯特拉**/
void Dijkstra(Graph& G, int start, int es, char** s)
{
	for (int i = 1; i <= G.sum; i++)
	{
		if (G.M[start][i])
		{
			dist[i] = 0;
			path[i] = start;
		}
		else
		{
			dist[i] = Maxnum;
			path[i] = -1;
		}
		visited[i] = 0;
	}//初始化辅助数组
	visited[start] = 1;//将起始点设置为被选中状态
	int minunder = 0;
	for (int j = 1; j < G.sum; j++)//循环选中剩余的顶点
	{
		int mindist = Maxnum;
		for (int i = 1; i <= G.sum; i++)
		{
			if (dist[i] < mindist && !visited[i])
			{
				mindist = dist[i];
				minunder = i;
			}
		}//在 dist数组中寻找visited标志为false的元素的最小值
		if (dist[minunder] < Maxnum)
		{
			visited[minunder] = 1;//找到后将其设置为选中状态
			for (int i = 1; i <= G.sum; i++)
			{
				if (!visited[i] && G.M[minunder][i] && dist[i] > dist[minunder] + 1)//顶点j经过k到源点比原来更近
				{
					path[i] = minunder;
					dist[i] = dist[minunder] + 1;
				}
			}
		}
	}
	if (visited[es] == 1)
	{
		int i = es;
		s1.push(es);
		while (path[i] != start)
		{
			s1.push(path[i]);
			i = path[i];
		}
		s1.push(start);
		cout << endl;
		cout << "***经过最少站点的方案***" << endl;
		Print_Solution(s, G);
	}
	else
	{
		cout << "暂时未找到合适方案" << endl;
	}
}
/**选择正确公交车**/
bool Judge(int i, char* bs, char* es, char** s)
{
	//遍历文件,判断公交车是否符合要求
	int flag1 = 0, flag2 = 0;
	fstream bfile;
	bfile.open("Bus_Num.txt", ios::in);
	if (!bfile.good())
	{
		exit(1);
	}
	while (bfile.peek() != EOF && !bfile.eof() && !flag1 && !flag2)
	{
		bfile.getline(line, 1000);
		int temp = 0;
		temp = (line[0] - ('0' - 0)) * 100 + (line[1] - ('0' - 0)) * 10 + (line[2] - ('0' - 0));
		if (temp == i)
		{
			int start = 4;
			while (line[start] != '\n' && line[start] != '\0')
			{
				int x = 0;
				while (line[start] != '\n' && line[start] != '\0' && line[start] != ' ')
				{
					x = x * 10 + (line[start] - ('0' - 0));
					start++;
				}
				start++;
				if (Str_Cmp(bs, s[x - 1]))
				{
					flag1 = 1;
				}
				if (Str_Cmp(es, s[x - 1]))
				{
					flag2 = 1;
				}
			}
			break;
		}
	}
	bfile.close();
	if (flag1 && flag2)
	{
		return 1;
	}
	return 0;
}
void Dijkstra_2(Graph& G, int start, int es, char** s)
{
	int times = 0;
	cout << "***换乘最少的方案如下***" << endl;
	for (int i = 1; i <= G.sum; i++)
	{
		if (G.M[start][i])
		{
			dist[i] = 0;
			path[i] = start;
			Node* p = G.H[start].first;
			while (p)
			{
				if (Str_Cmp(p->name, s[i - 1]))
				{
					int t = pathbus[i][0];
					pathbus[i][t + 1] = p->bus_num;
					pathbus[i][0]++;
				}
				p = p->next;
			}
		}
		else
		{
			dist[i] = Maxnum;
			path[i] = -1;
		}
		visited[i] = 0;
	}//初始化辅助数组
	visited[start] = 1;//将起始点设置为被选中状态
	int minunder = 0;
	for (int j = 1; j < G.sum; j++)
	{
		int mindist = Maxnum;
		for (int i = 1; i <= G.sum; i++)
		{
			if (dist[i] < mindist && !visited[i])
			{
				mindist = dist[i];
				minunder = i;
			}
		}//在 dist数组中寻找visited标志为false的元素的最小值
		if (dist[minunder] < Maxnum)
		{
			visited[minunder] = 1;
			for (int i = 1; i <= G.sum; i++)//对整体进行依次改动
			{
				if (!visited[i] && G.M[minunder][i] && dist[i] > dist[minunder])//如果可以对该点进行改动
				{
					pathbus[i][0] = 0;
					int change = 1;//是否需要换乘的标志
					Node* p = G.H[minunder].first;
					while (p)
					{
						if (Str_Cmp(s[i - 1], p->name))//选出该点获取信息
						{
							for (int t = 1; t <= pathbus[minunder][0]; t++)
							{
								if (pathbus[minunder][t] == p->bus_num)
								{
									change = 0;//不需要换乘
									changebus[i] = 0;
									path[i] = minunder;
									int start = pathbus[i][0];
									pathbus[i][start + 1] = p->bus_num;//将不需要换乘乘坐的公交号存入
									dist[i] = dist[minunder];
									pathbus[i][0]++;
								}
							}
						}
						p = p->next;
					}
					if (change)//虽然可以到达,还是需要换乘
					{
						changebus[i] = 1;
						p = G.H[minunder].first;
						while (p)
						{
							if (Str_Cmp(s[i - 1], p->name))//选出该点获取信息
							{
								int start = pathbus[i][0];
								pathbus[i][start + 1] = p->bus_num;//将不需要换乘乘坐的公交号存入
								dist[i] = dist[minunder] + 1;
								pathbus[i][0]++;
								path[i] = minunder;
							}
							p = p->next;
						}
					}
				}
			}
		}

	}
	int anstart = 1;
	if (visited[es] == 1)
	{
		int i = es;
		s2.push(es);
		while (path[i] != start)
		{
			s2.push(path[i]);
			i = path[i];
		}
		s2.push(start);
		while (!s2.empty())
		{
			ans[anstart++] = s2.top();
			s2.pop();
		}
		anstart--;
		for (int k = 1; k <= anstart; k++)
		{
			int sk = k;
			int nk = k;
			if (!changebus[ans[nk]])//起始点
			{
				while (!changebus[ans[nk]] && nk <= anstart)
				{
					nk++;
				}
				nk--;
				Node* x = G.H[ans[sk]].first;
				while (x)//遍历
				{
					if (Judge(x->bus_num, s[ans[sk] - 1], s[ans[nk] - 1], s))
					{
						times++;
						cout << "    (乘" << x->bus_num << "路)" << endl;
						while (sk <= nk)
						{
							cout << s[ans[sk] - 1] << " -> ";
							sk++;
						}
						cout << "下车";
						cout << endl;
						break;
					}
					x = x->next;
				}
			}
			else//非起始点
			{
				sk--;
				nk++;
				while (!changebus[ans[nk]] && nk <= anstart)
				{
					nk++;
				}
				nk--;
				Node* x = G.H[ans[sk]].first;
				while (x)//遍历
				{
					if (Judge(x->bus_num, s[ans[sk] - 1], s[ans[nk] - 1], s))
					{
						times++;
						cout << "  (乘 " << x->bus_num << "路)" << endl;
						while (sk <= nk)
						{
							cout << s[ans[sk] - 1] << " -> ";
							sk++;
						}
						cout << "下车";
						cout << endl;
						break;
					}
					x = x->next;
				}
			}
			k = nk;
		}
		cout << endl;
		cout << "    *共换乘" << times - 1 << "次" << endl;
	}
	else
	{
		cout << "暂时未找到合适方案" << endl;
	}
}
Main.cpp
#include <iostream>
#include "Bus.h"
using namespace std;
char* s[2000];
int k = 0;
int bs = 0, es = 0;
char bstion[100], estion[100];
Graph G;
Graph G2;
int main()
{
	G.sum = 929;
	Get_Information_From_File(s, k, G);
	Creat_Graph(G, s);
	cout << "输入起始站:";
	cin >> bstion;
	cout << "输入终点站:";
	cin >> estion;
	cout << endl;
	Check_Station(G, bstion, estion, bs, es, s);
	Dijkstra(G, bs, es, s); 
	Dijkstra_2(G, bs, es, s);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要制作一个查询公交线路的Android应用程序,可以按照以下步骤进行: 1. 首先,需要创建一个新的Android项目,并导入Android Studio中。在Android Studio的欢迎界面中选择“Create New Project”,并按照提示进行设置。 2. 接下来,需要设计应用程序的用户界面。可以使用XML布局文件创建应用程序的界面,包括输入线路号码的文本框和搜索按钮。 3. 在应用程序的主活动中,编写代码来处理用户的输入和点击搜索按钮的时间。可以使用Java语言编写处理逻辑。当用户点击搜索按钮时,获取用户输入的线路号码,并使用该号码向公交线路查询API发送请求。 4. 为了查询公交线路,需要找到一个可靠的公交线路查询API。可以根据自己的需求选择一个合适的API,并按照API提供的文档来使用。 5. 在代码中使用API提供的功能,发送查询请求并获取公交线路的相关信息。根据API的响应,可以显示公交线路的详细信息,如线路名称、起始站点、终点站点等。 6. 最后,为了提供更好的用户体验,可以添加一些额外的功能,如保存用户最近的查询记录、显示公交线路的车辆实时位置等。 总之,制作查询公交线路的Android应用程序,需要创建项目、设计界面、编写代码处理用户输入和查询请求,并使用公交线路查询API来获取相关信息。在此基础上,可以添加其他功能来提升用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值