【题目】公交线路图
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(20sizeof(char));BUSES[i][1]= (char)malloc(20sizeof(char));BUSES[i][2]= (char)malloc(20sizeof(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(20sizeof(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,其实自己都可以慢慢解决,就是时间问题,不能急躁,这次课设,从中受益匪浅。