【题目】公交线路图
1、数据格式
用了四个txt文件:
第一个:BUSES.txt
第一列为公交线路的名称,第二列为起点,第三列为终点。
比如第一行代表
一路上行公交从余店路开往中百超市
第二个:
STATIONS.txt
记录如图的站点信息。
第三个:
ROUTES.txt
记录路线信息,分别为
线路编号 站点编号 站点编号 距离
- 01 500
意思是一路上行,从余店路开往中山公园,距离为500
第四个:
MAPNUM.txt
分别记录 BUSES,STATIONS, ROUTES的大小
2、数据结构(读文件创建图)
通过函数load_data()把文件里的数据读到全局变量数组中
int load_data()
{
FILE* f1;
FILE* f2;
FILE* f3;
FILE* f4;
f1 =fopen("D:\\MyWorkSpace\\c\\公交线路图\\ROUTES.txt","r");
f2 =fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","r");
f3 =fopen("D:\\MyWorkSpace\\c\\公交线路图\\STATIONS.txt","r");
f4 =fopen("D:\\MyWorkSpace\\c\\公交线路图\\MAPNUM.txt","r");
if(f1==NULL)
{
printf("load ROUTES.txt errer!\n");
exit(0);
}
else if(f2==NULL)
{
printf("load BUSES.txt errer!\n");
exit(0);
}
else if(f3==NULL)
{
printf("load STATIONS.txt errer!\n");
exit(0);
}
else if(f4==NULL)
{
printf("load MAPNUM.txt errer!\n");
exit(0);
}
else
{
fscanf(f4,"%d%d%d",&BUS_NUM,&STATION_NUM,&ROUTE_NUM);
fclose(f4);
ROUTES= malloc(sizeof(int)*ROUTE_NUM * 4);
BUSES= malloc(sizeof(char*)*BUS_NUM* 3);
STATIONS= (char**)malloc(sizeof(char*)*STATION_NUM);
int i;
for(i=0;i<ROUTE_NUM;i++)
{
fscanf(f1,"%d%d%d%d",&ROUTES[i][0],&ROUTES[i][1],&ROUTES[i][2],&ROUTES[i][3]);
}
for(i=0;i<BUS_NUM;i++)
{
BUSES[i][0]= (char*)malloc(20*sizeof(char));
BUSES[i][1]= (char*)malloc(20*sizeof(char));
BUSES[i][2]= (char*)malloc(20*sizeof(char));
fscanf(f2,"%s%s%s",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
for(i=0;i<STATION_NUM;i++)
{
STATIONS[i]= (char*)malloc(20*sizeof(char));
fscanf(f3,"%s",STATIONS[i]);
}
}
fclose(f1);
fclose(f2);
fclose(f3);
return 0;
}
采用邻接表储存公交线路图:
通过void LoadMapDate()函数把数组的数据载入全局变量g_sMap中。
typedef struct Bus
{
char* name; //公交线路名
int start; //起点
int end; //终点
int* stations; //公交线路站点索引数组
int station_num;//站点个数
}Bus;
//2、定义结构体STATION代表一个站点
typedef struct Station
{
char* station; //站点名
struct Route* routes; //从该站点出发的所有下行路线的链域
}Station;
//3、定义结构体ROUTE代表公交线路中的一个路段(邻接表结点)
typedef struct Route
{
int station; //指向的站点索引号
int bus; //公交索引号
int distance; //两点之间公路的距离
bool visited; //遍历时的标识符
struct Route* next; //起始站点相同的,下一条下行路线
}Route;
//4、定义结构体BUSMAP存储整个公交地图信息
typedef struct BusMap
{
Bus* buses; //公交线路数组
Station* stations; //站点数组
int station_num; //站点数
int bus_num; //公交线路数
}BusMap;
BusMap g_sMap; //定义全局变量
3、查询公交线路和站点信息
(1) 查询公交线路
通过QueryBus函数查询
int QueryBus(char* pBus,char** stations)
{
int sum=2; //记录站点个数,起点和终点没算
//1、查找公交
int flagBus=FindBus(pBus); //找到公交线路的索引
//2、找到公交及信息
char* nStart=BUSES[flagBus][1];
char* nEnd=BUSES[flagBus][2];
//3、输出起始站点
printf("[%s线路]\t从[%s]开往[%s]\n",pBus,nStart,nEnd);
//4、输出各站点
int flagStart = FindStation(nStart); //找到起点的索引,从而找到后面路线
int flagEnd = FindStation(nEnd);
Station* pStStation = &g_sMap.stations[flagStart];
Route* pStRoute = pStStation->routes;
while(pStRoute->bus!=flagBus) //找到该公交线路的第一条路线
{
pStRoute=pStRoute->next;
}
printf("%s->",nStart); //输出起始站点
while(pStRoute->station!=flagEnd) //如果路线不是最后一条路线
{
printf("%s->",*(stations+(pStRoute->station)));
sum++;
pStStation = &g_sMap.stations[pStRoute->station]; //换到下一个路线的站点
pStRoute = pStStation->routes; //下一个站点的第一条路线,不是该公交线路的第一条路线
while(pStRoute->bus!=flagBus)
{
pStRoute=pStRoute->next;
}
}
printf("%s\n",nEnd);
return sum;
}
运行结果为:
- 查询站点信息
函数代码如下:
//创建QueryStation函数,实现查询站点信息,输出该站点所经线路信息
int QueryStation(char* pStation,char** buses)
{
int flag[BUS_NUM];
int i;
for(i=0;i<BUS_NUM;i++)
{
flag[i]=-1;
}
int sum=0; //记录路线的总数
int flagStation=FindStation(pStation); //找到该站点的索引
Station* pStStation=&g_sMap.stations[flagStation];
Route* pStRoute=pStStation->routes;
int j=0;
while(pStRoute!=NULL)
{
flag[j]=pStRoute->bus;
j++;
pStRoute=pStRoute->next;
}
for(i=0;flag[i]!=-1;i++)
{
printf("%s\n",*(buses+(flag[i])*3));
//printf("%s\n",*(buses+((flag[i])+1)*3));
sum++;
}
return sum;
}
运行结果为:
4、查询两站点之间的路线,找到至多换乘1次的路线,并输出结果。
这个算法我是先写一个函数找到两个站点之间的直接路径,就是不换乘即可到达的路径。
通过bool directPath(char* pStart,char* pEnd,int* direct_bus)函数判断两个站点之间是否有不换乘的直接路径,并且把两点之间的直接路径公交放在直达direct_bus数组里。
找换乘的路线,首先找到换乘的站点,通过遍历除了起点和终点的站点,调用directPath()函数,每个站点到起点有一个直达数组,每个站点到终点也有一个直达数组,通过循环搭配,即可找出所有的换乘一次的路线
即函数void Show_directPath(char* pStart,char* pEnd,int nBus)
公交线路图为:
函数代码如下:
void Show_transferPath(char* pStart,char* pEnd)
{
int nStart = FindStation(pStart);
int nEnd = FindStation(pEnd);
int path_sum=0;
int i=0,j=0;
//先输出直达的路线
int pathdirect_bus[BUS_NUM];
for(i=0;i<BUS_NUM;i++)
{
pathdirect_bus[i]=-1;
}
bool is_pathdirect=directPath(pStart,pEnd,pathdirect_bus); //判断是否有直达,如果有,把直达公交放在数组中
if(is_pathdirect==true)
{
for(i=0;pathdirect_bus[i]!=-1;i++)
{
path_sum++;
printf("第%d条路线为:\n",path_sum);
Show_directPath(pStart,pEnd,pathdirect_bus[i]);
printf("\n\n");
}
}
//换乘一次的路线
int stations[STATION_NUM-2]; //记录每个站点的索引
i=0;
for(i=0;i<STATION_NUM;i++)
{
int station_flag = FindStation(STATIONS[i]);
if(station_flag!=nStart&&station_flag!=nEnd)
{
stations[j]=station_flag;
j++;
}
}
int Start_directbus[BUS_NUM];
int End_directbus[BUS_NUM];
i=0;
for(i=0;i<BUS_NUM;i++)
{
Start_directbus[i]=-1;
End_directbus[i]=-1;
}
i=0;j=0;
int m,n;
for(i=0;i<(STATION_NUM-2);i++)
{
//必须要给数组重置
for(j=0;j<BUS_NUM;j++)
{
Start_directbus[j]=-1;
End_directbus[j]=-1;
}
bool Start_middle = directPath(pStart,STATIONS[stations[i]],Start_directbus);
bool End_middle = directPath(STATIONS[stations[i]],pEnd,End_directbus);
if(Start_middle==true&&End_middle==true)
{
for(m=0;Start_directbus[m]!=-1;m++)
{
for(n=0;End_directbus[n]!=-1;n++)
{
if(Start_directbus[m]!=End_directbus[n])
{
path_sum++;
printf("第%d条路线为:\n",path_sum);
Show_directPath(pStart,STATIONS[stations[i]],Start_directbus[m]);
printf("(在此站换乘)\n");
Show_directPath(STATIONS[stations[i]],pEnd,End_directbus[n]);
printf("\n\n");
}
}
}
}
}
if(path_sum==0)
{
printf("没有符合要求的路线!\n");
}
}
运行结果为:
- 修改公交线路和站点信息,保存文件
通过函数modify把全局变量的数据修改,然后再写入文件中保存,
最后调用load_data()函数和void LoadMapDate()函数把数组的数据再载入全局变量g_sMap中。
修改某一条线路时,要动态设置数组,删一条线路,ROUTES_NUM就应该减1,ROUTES文档再重新写入,如果删除的站点是某一条线路的起点和终点,还需要修改BUSES文档。
代码如下:
int modify_data()
{
int ch;
char name1[20],name2[20];
int distance;
int i;
printf("1、修改站点名称\n");
printf("2、修改线路距离\n");
printf("3、删除某一公交站点\n");
ch=getch()-48;
switch(ch)
{
case 1:
printf("请输入要修改的站点原名称:");
scanf("%s",name1);
printf("请输入修改后的站点名称:");
scanf("%s",name2);
int flag = FindStation(name1);
STATIONS[flag]=name2;
//LoadMapDate(); //重新加载
FILE* f1=fopen("D:\\MyWorkSpace\\c\\公交线路图\\STATIONS.txt","w");
if(f1==NULL)
{
printf("open error!\n");
exit(0);
}
for(i=0;i<STATION_NUM;i++)
{
fprintf(f1,"%s ",STATIONS[i]);
}
fclose(f1);
for(i=0;i<BUS_NUM;i++)
{
//printf("%d\n",g_sMap.buses[i].start);
if(flag==g_sMap.buses[i].start)
{
if(i%2==0)
{
BUSES[i][1]=name2;
BUSES[i+1][2]=name2;
}
else
{
BUSES[i][1]=name2;
BUSES[i-1][2]=name2;
}
}
}
f1=fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","w");
if(f1==NULL)
{
printf("open BUSES error!\n");
exit(0);
}
else
{
for(i=0;i<BUS_NUM;i++)
{
fprintf(f1,"%s %s %s\n",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
fclose(f1);
}
printf("\n修改成功!\n");
break;
case 2:
printf("请输入想要修改的(相邻)两个站点:\n");
printf("站点一:");
scanf("%s",name1);
printf("站点二:");
scanf("%s",name2);
printf("请输入这两站之间的距离(单位:米):");
scanf("%d",&distance);
int flag1 = FindStation(name1);
int flag2 = FindStation(name2);
for(i=0;i<ROUTE_NUM;i++)
{
if(ROUTES[i][1]==flag1)
{
if(ROUTES[i][2]==flag2)
{
ROUTES[i][3]=distance;
}
}
else if(ROUTES[i][1]==flag2)
{
if(ROUTES[i][2]==flag1)
{
ROUTES[i][3]=distance;
}
}
}
LoadMapDate(); //重新加载
FILE* f2 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\ROUTES.txt","w");
for(i=0;i<ROUTE_NUM;i++)
{
fprintf(f2,"%d %d %d %d\n",ROUTES[i][0],ROUTES[i][1],ROUTES[i][2],ROUTES[i][3]);
}
fclose(f2);
break;
case 3:
printf("请输入要删除哪条公交线路的哪个站点:\n");
printf("请输入公交线路:");
scanf("%s",name1);
printf("请输入站点:");
scanf("%s",name2);
int flag3 = FindStation(name2); //站点索引
int flag4 = FindBus(name1); //公交线路索引
if(flag3==g_sMap.buses[flag4].start)
{
if(flag4%2==0)
{
int modify1=Find_ROUTES_1(flag4,flag3);
int modstart = ROUTES[modify1][2]; //先记录更新的起点
delete_ROUTES(modify1);
load_data();
int modify2=Find_ROUTES_2(flag4+1,flag3);
delete_ROUTES(modify2);
load_data();
BUSES[flag4][1]=STATIONS[modstart];
BUSES[flag4+1][2]=STATIONS[modstart];
FILE* f4 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","w");
if(f4==NULL)
{
printf("open BUSES error!\n");
exit(0);
}
for(i=0;i<BUS_NUM;i++)
{
fprintf(f4,"%s %s %s\n",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
fclose(f4);
}
else
{
int modify1=Find_ROUTES_1(flag4,flag3);
int modstart = ROUTES[modify1][2];
delete_ROUTES(modify1);
load_data();
int modify2=Find_ROUTES_2(flag4-1,flag3);
delete_ROUTES(modify2);
load_data();
BUSES[flag4][1]=STATIONS[modstart];
BUSES[flag4-1][2]=STATIONS[modstart];
FILE* f4 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","w");
if(f4==NULL)
{
printf("open BUSES error!\n");
exit(0);
}
for(i=0;i<BUS_NUM;i++)
{
fprintf(f4,"%s %s %s\n",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
fclose(f4);
}
load_data();
}
else if(flag3==g_sMap.buses[flag4].end)
{
if(flag4%2==0)
{
int modify1=Find_ROUTES_2(flag4,flag3);
int modend = ROUTES[modify1][1]; //记录更新的终点
//printf("路线索引=%d\n更新的终点索引=%d\n",modify1,modend);
delete_ROUTES(modify1);
load_data();
int modify2=Find_ROUTES_1(flag4+1,flag3);
delete_ROUTES(modify2);
load_data();
BUSES[flag4][2]=STATIONS[modend];
BUSES[flag4+1][1]=STATIONS[modend];
FILE* f4 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","w");
for(i=0;i<BUS_NUM;i++)
{
fprintf(f4,"%s %s %s\n",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
fclose(f4);
}
else
{
int modify1=Find_ROUTES_2(flag4,flag3);
int modend = ROUTES[modify1][1];
delete_ROUTES(modify1);
load_data();
int modify2=Find_ROUTES_1(flag4-1,flag3);
delete_ROUTES(modify2);
load_data();
BUSES[flag4][2]=STATIONS[modend];
BUSES[flag4-1][1]=STATIONS[modend];
FILE* f4 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\BUSES.txt","w");
for(i=0;i<BUS_NUM;i++)
{
fprintf(f4,"%s %s %s\n",BUSES[i][0],BUSES[i][1],BUSES[i][2]);
}
fclose(f4);
}
}
else
{
printf("请输入删除该站点所形成的新路线的距离是(单位:米):");
scanf("%d",&distance);
if(flag4 % 2!=0)
{
flag4--;
}
if(flag4 % 2==0)
{
FILE* f3 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\ROUTES.txt","w");
int modify=Find_ROUTES_2(flag4,flag3);
ROUTES[modify][2]=ROUTES[modify+1][2];
ROUTES[modify][3]=distance;
for(i=0;i<ROUTE_NUM;i++)
{
fprintf(f3,"%d %d %d %d\n",ROUTES[i][0],ROUTES[i][1],ROUTES[i][2],ROUTES[i][3]);
}
fclose(f3);
delete_ROUTES(modify+1);
load_data(); //把修改的文件再导入
f3 = fopen("D:\\MyWorkSpace\\c\\公交线路图\\ROUTES.txt","w");
modify = Find_ROUTES_2(flag4+1,flag3);
ROUTES[modify][2]=ROUTES[modify+1][2];
ROUTES[modify][3]=distance;
for(i=0;i<ROUTE_NUM;i++)
{
fprintf(f3,"%d %d %d %d\n",ROUTES[i][0],ROUTES[i][1],ROUTES[i][2],ROUTES[i][3]);
}
fclose(f3);
delete_ROUTES(modify+1);
load_data(); //把修改的文件再导入
}
}
LoadMapDate();
printf("\n删除成功!\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
load_data();
LoadMapDate();
return 0;
}
第一个功能修改前:
例如:
二路上行终点是火车站
进行修改:
修改后:
因为输入的是某一个线路的起始或者终止站点,那么BUSES文档也会修改,如果只是一个中间站点,则只修改STATIONS文档,数据具有关联性。
此时文档为:
又例如第三个功能,删除某一条公交线路的某一条路线
例如删除二路上行的终点火车站。
那么此时BUSES文档和ROUTES文档都需要修改。
修改前二路上行的路线如下,终点是火车站。
修改时:
修改后,此时二路上行终点变为中百超市,结果如图:
而此时的文档情况为:
二路上行和二路下行的终点起点都进行了修改
ROUTES文档也进行了删除和修改
因此减少了两条路线,二路上行减少一条,二路下行也减少一条,
所以ROUTES数组大小从34变为32
- 设计总结
这个实验前前后后做了一个多星期,因为有些东西忘了,又翻书复习,公交线路图之前在学校做过简单的,但是没有存入文件这个功能,又在网上以及书上学习了一些读取文件和写进文件的方法,最后因为还要有修改数据的功能,所以对于之前定义的全局变量数组,数组大小不能定义为静态的,而是要采用动态的定义二维数组,再通过malloc进行动态分配空间,有一次在宏定义None时,把None定义为0了,结果后面测试的时候总是发生错误,后来发现当没找到路线时,赋值为None,而一路上行的索引也为0,就导致了冲突,后来把None改为-1就解决了问题,通过这次课设,更加了解了邻接表储存图的操作,还学会了文件读取和写入的操作,通过模块化,把主页面和功能分开,当时读写文件的时候,中文字符一直乱码,查了一下把txt文件的编码改了一下,总之乱码一般就是编码不一致导致的,不管遇到问题还是bug,其实自己都可以慢慢解决,就是时间问题,不能急躁,这次课设,从中受益匪浅。