1.任务:
[问题描述]
上网下载真实南京公交线路图,建立南京主要公交线路图的存储结构。
[基本要求]
(1)输入任意两站点,给出转车次数最少的乘车路线。
(2)输入任意两站点,给出经过站点最少的乘车路线。
2.采用的数据结构
使用顺序结构,队列和图
3.算法设计思想
建立公交车类型结构,对于每辆车的编号,经过的站点数和经过的站点编号进行存储。建立公交站台类型结构,对于每个编号的公交站点的名称,经过该站点的公交车的数量和编号进行存储。
当寻找经过站点数最少的方案时,使用广度优先遍历,逆向存储,从终点站起,对每个在栈中的站点的公交线路进行遍历,使该线路上该站点的前后站(未进栈过的)依次进栈并标记,记录进栈站点的后一站点和公交线路,直至找到起点站。
当寻找换乘次数最少的方案时,使用深度优先遍历,逆向存储,从终点起,对每个在栈中的站点的公交线路进行遍历,使该线路上每一个未进栈的站点进栈,并标记其后一站点和公交线路,直至找到起点站为止。
4.源程序
#include <iostream>
#include <string.h>
#include <fstream>
#include <sstream>
#include <string>
#include <windows.h>
using namespace std;
typedef struct Bus
{
int No; //该公交车的编号
int StationCount; //该公交车经过的站点数量
int BusRoute[80]; //该公交车依次经过的站点编号
}Bus;
typedef struct Station
{
char StationName[60]; //站点名称
int BusCount; //经过该站点的公交车数量
short int bus[35]; //经过该站点的公交车的编号
}Station;
typedef struct BusMap
{
Bus bus[1000];
Station station[10000];
int BusCount; //公交车数量
int StationCount; //站点数量
}BusMap;
int GetBusStation(BusMap &M, char busname[60]) //获取站台名对应的编号
{
for (int i=1;i<=M.StationCount;i++)
{
if (strcmp(M.station[i].StationName,busname)==0)
{
return i;
}
}
return 0;
}
int IncreaseBusStation(BusMap &M, char busname[60])
{
int num=GetBusStation(M,busname);
if (num==0)
{
strcpy(M.station[++M.StationCount].StationName,busname);
num=M.StationCount;
}
M.bus[M.BusCount].BusRoute[M.bus[M.BusCount].StationCount]=num;
M.station[num].bus[++M.station[num].BusCount] = M.bus[M.BusCount].No;
for (int i=0;i<60; i++)
{
busname[i]='\0';
}
return num;
}
int CreateMap(BusMap &M) //创建图
{
M.BusCount=0;
M.StationCount=0;
for (int i=0; i<1000;i++)
{
M.bus[i].StationCount=1;
}
for (int i=0;i<10000;i++)
{
M.station[i].BusCount=0;
}
int num=0;
char busname[60];
char ch;
FILE *fp;
if ((fp=fopen("南京公交线路.txt", "r"))==NULL)
{
printf("文件打开失败\n");
exit(0);
}
fscanf(fp, "%d", &M.bus[++M.BusCount].No);
while (ch!=' ')
{
ch=fgetc(fp);
}
while (1)
{
ch=fgetc(fp);
if (feof(fp))
{
IncreaseBusStation(M,busname);
break;
}
if(ch==' ')
{
continue;
}
if(ch==',')
{
IncreaseBusStation(M,busname);
num=0;
M.bus[M.BusCount].StationCount++;
continue;
}
if(ch=='\n')
{
IncreaseBusStation(M,busname);
num=0;
char chh;
chh=fgetc(fp);
if (feof(fp))
{
break;
}
fseek(fp, -1L, 1);
fscanf(fp, "%d", &M.bus[++M.BusCount].No);
while (ch != ' ')
{
ch = fgetc(fp);
}
continue;
}
busname[num++]=ch;
}
fclose(fp);
}
int GetBus(BusMap &M, int No) //获取公交线路对应的编号
{
for (int i=1; i<= M.BusCount;i++)
{
if (M.bus[i].No == No)
{
return i;
}
}
return 0;
}
typedef struct LNode //队列基本操作
{
int data;
struct LNode *next;
}LNode,*QueuePtr;
typedef struct LinkQueue
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
void InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=(LNode *)malloc(sizeof(LNode));
if(Q.front==NULL) exit -1;
Q.front->next=NULL;
}
int QueueEmpty(LinkQueue Q)
{
if (Q.front!=Q.rear)
{
return 0;
}
else
{
return 1;
}
}
void EnQueue(LinkQueue &Q,int e)
{
LNode *s;
s=(LNode *) malloc(sizeof(LNode));
if(s==NULL) exit -1;
s->data=e;
Q.rear->next=s;
Q.rear=s;
}
int DeQueue(LinkQueue &Q)
{
LNode *p;
int e;
if (Q.front==Q.rear) return -1;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear == p)
{
Q.rear=Q.front;
}
free(p);
return e;
}
typedef struct info //PreStation记录前一站号,busno记录经过该站所乘坐的公交车
{
int NextStation;
int busno;
short int visited;
}info;
info k[10000];
int FindLeastStationNum(BusMap &M,char StartStation[60],char EndStation[60]) //寻找乘坐站数最少的方案
{
int start,end;
start=GetBusStation(M,StartStation);
end=GetBusStation(M,EndStation);
for(int i=1;i<10000;i++)
{
k[i].visited=0;
k[i].NextStation=i;
k[i].busno=0;
}
LinkQueue Q;
InitQueue(Q);
EnQueue(Q,end); //倒序查找
k[end].visited=1;
int count=1;
while(1)
{
count++;
EnQueue(Q,-1); //-1为标记
while(Q.front!=Q.rear)
{
end=DeQueue(Q);
if(end==-1)
{
break;
}
for(int i=1;i<=M.station[end].BusCount;i++) //遍历所有经过此站的线路
{
int b;
b=GetBus(M,M.station[end].bus[i]);
for(int j=1;j<=M.bus[b].StationCount;j++)
{
if (M.bus[b].BusRoute[j]==end) //找到该路车中该站点的序号
{
if (M.bus[b].BusRoute[j+1]==start || M.bus[b].BusRoute[j-1]==start) //下一站或上一站为起始站
{
int bus=k[end].busno;
printf("最少经过%d个站点\n\n",count);
cout<<M.station[start].StationName;
printf("(乘坐%d路)->", M.bus[b].No);
count--;
while(count--)
{
if (count==0)
{
cout<<M.station[end].StationName<<"(到达终点,下车)"<<endl;
}
else
{
cout<<M.station[end].StationName;
printf("(乘坐%d路)->" ,bus);
}
end=k[end].NextStation;
bus=k[end].busno;
}
return 1;
}
if ((k[M.bus[b].BusRoute[j-1]].visited==0) && (j-1>0) ) //当前一站存在且未被访问
{
k[M.bus[b].BusRoute[j-1]].busno = M.bus[b].No;
k[M.bus[b].BusRoute[j-1]].NextStation=end;
EnQueue(Q, M.bus[b].BusRoute[j-1]);
k[M.bus[b].BusRoute[j-1]].visited=1;
}
if ((k[M.bus[b].BusRoute[j+1]].visited==0) && (j+1<=M.bus[b].StationCount)) //当后一站存在且未被访问
{
k[M.bus[b].BusRoute[j+1]].busno=M.bus[b].No;
k[M.bus[b].BusRoute[j+1]].NextStation=end;
EnQueue(Q, M.bus[b].BusRoute[j+1]);
k[M.bus[b].BusRoute[j+1]].visited=1;
}
break;
}
}
}
}
}
}
int FindLeastTransfer(BusMap &M,char StartStation[60],char EndStation[60]) //寻找转车最少的方案
{
int start,end;
start=GetBusStation(M,StartStation);
end=GetBusStation(M,EndStation);
for(int i=1;i<10000;i++)
{
k[i].visited=0;
k[i].NextStation=i;
k[i].busno=0;
}
LinkQueue Q;
InitQueue(Q);
EnQueue(Q,end); //倒序查找
k[end].visited=1;
int count=1;
while(1)
{
EnQueue(Q,-1);
while(Q.front!=Q.rear)
{
end=DeQueue(Q);
if(end==-1)
{
count++;
break;
}
for(int i=1;i<=M.station[end].BusCount;i++)
{
int b;
b=GetBus(M,M.station[end].bus[i]);
for(int j=1;j<=M.bus[b].StationCount;j++)
{
if(M.bus[b].BusRoute[j]==start)
{
int bus;
bus=k[end].busno;
printf("至少需要乘坐%d班公交车\n",count);
cout<<M.station[start].StationName;
printf("(乘坐%d路公交车)->",M.bus[b].No);
while(count--)
{
if(count==0)
{
cout<<M.station[end].StationName<<"(到达终点,请下车!)"<<endl;
}
else
{
cout<<M.station[end].StationName;
printf("(换乘%d路车)->",bus);
}
end=k[end].NextStation;
bus=k[end].busno;
}
return 1;
}
else if(k[M.bus[b].BusRoute[j]].visited==0)
{
k[M.bus[b].BusRoute[j]].visited=1;
k[M.bus[b].BusRoute[j]].busno=M.bus[b].No;
k[M.bus[b].BusRoute[j]].NextStation=end;
EnQueue(Q,M.bus[b].BusRoute[j]);
}
}
}
}
}
}
int FindLeastTransfer1(BusMap &M,char StartStation[60],char EndStation[60]) //寻找转车最少的方案(具体)
{
int start,end;
start=GetBusStation(M,StartStation);
end=GetBusStation(M,EndStation);
int end1=end;
for(int i=1;i<10000;i++)
{
k[i].visited=0;
k[i].NextStation=i;
k[i].busno=0;
}
LinkQueue Q;
InitQueue(Q);
EnQueue(Q,end); //倒序查找
k[end].visited=1;
while(1)
{
EnQueue(Q,-1);
while(Q.front!=Q.rear)
{
end=DeQueue(Q);
if(end==-1)
{
break;
}
for(int i=1;i<=M.station[end].BusCount;i++)
{
int b;
b=GetBus(M,M.station[end].bus[i]);
int loc;
for(int j=1;j<=M.bus[b].StationCount;j++)
{
if(M.bus[b].BusRoute[j]==end)
{
loc=j;
break;
}
}
for(int j=loc+1;j<=M.bus[b].StationCount;j++)
{
if(M.bus[b].BusRoute[j]==start)
{
int bus;
bus=k[end].busno;
printf("具体公交路线如下:\n");
cout<<M.station[start].StationName;
printf("(乘坐%d路公交车)->",M.bus[b].No);
while(end!=end1)
{
cout<<M.station[end].StationName;
printf("(乘坐%d路车)->",bus);
end=k[end].NextStation;
bus=k[end].busno;
}
cout<<M.station[end].StationName<<"(到达终点,请下车!)"<<endl;
return 1;
}
else if(k[M.bus[b].BusRoute[j]].visited==0)
{
k[M.bus[b].BusRoute[j]].visited=1;
k[M.bus[b].BusRoute[j]].busno=M.bus[b].No;
k[M.bus[b].BusRoute[j]].NextStation=M.bus[b].BusRoute[j-1];
EnQueue(Q,M.bus[b].BusRoute[j]);
}
}
for(int j=loc-1;j>=1;j--)
{
if(M.bus[b].BusRoute[j]==start)
{
int bus;
bus=k[end].busno;
printf("具体公交路线如下:\n");
cout<<M.station[start].StationName;
printf("(乘坐%d路公交车)->",M.bus[b].No);
while(end!=end1)
{
cout<<M.station[end].StationName;
printf("(乘坐%d路车)->",bus);
end=k[end].NextStation;
bus=k[end].busno;
}
cout<<M.station[end].StationName<<"(到达终点,请下车!)"<<endl;
return 1;
}
else if(k[M.bus[b].BusRoute[j]].visited==0)
{
k[M.bus[b].BusRoute[j]].visited=1;
k[M.bus[b].BusRoute[j]].busno=M.bus[b].No;
k[M.bus[b].BusRoute[j]].NextStation=M.bus[b].BusRoute[j+1];
EnQueue(Q,M.bus[b].BusRoute[j]);
}
}
}
}
}
}
int main()
{
BusMap M;
CreateMap(M);
char start[60],end[60];
printf("请输入起点:");
cin>>start;
fflush(stdin);
printf("请输入终点:");
cin>>end;
printf("----------------------------------\n\n");
if(GetBusStation(M,start)==0 || GetBusStation(M,end)==0)
{
printf("站点输入有误!\n");
}
else
{
FindLeastStationNum(M,start,end);
printf("\n----------------------------------\n\n");
FindLeastTransfer(M,start,end);
printf("\n");
FindLeastTransfer1(M,start,end);
}
return 0;
}
5.源程序测试数据及结果
公交线路提示测试数据及结果
6.存在问题及解决办法
在存储车站和公交路线时,使用了数组,无法把握空间,可能会产生大空间的浪费或是溢出的问题。但是由于各个站点经过的公交车数不同,无法使用链表进行存储。可以考虑在之后采用动态存储,例如vector等,不易产生空间问题。
7.文档内容
txt文档中每一行表示一个线路,线路号(注意不一定连续,可能有部分数字线路不存在)和后面站名之间用空格分隔,各站名之间用英语逗号分隔。
(好像没有找到上传文档链接的方法,有需要可以私发邮箱)