数据结构课程设计——公交线路图,包含源代码和注释,任务和报告文档,手绘图,以及一个演示视频,视频里的编译环境是codeblocks

【题目】公交线路图

1、数据格式

用了四个txt文件:

第一个:BUSES.txt

第一列为公交线路的名称,第二列为起点,第三列为终点。

比如第一行代表

一路上行公交从余店路开往中百超市

第二个:

STATIONS.txt

记录如图的站点信息。

第三个:

ROUTES.txt

记录路线信息,分别为

线路编号 站点编号 站点编号 距离

  1. 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;
}
运行结果为:

  1. 查询站点信息

函数代码如下:

//创建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");

}

}

运行结果为:

  1. 修改公交线路和站点信息,保存文件
    通过函数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

  1. 设计总结

这个实验前前后后做了一个多星期,因为有些东西忘了,又翻书复习,公交线路图之前在学校做过简单的,但是没有存入文件这个功能,又在网上以及书上学习了一些读取文件和写进文件的方法,最后因为还要有修改数据的功能,所以对于之前定义的全局变量数组,数组大小不能定义为静态的,而是要采用动态的定义二维数组,再通过malloc进行动态分配空间,有一次在宏定义None时,把None定义为0了,结果后面测试的时候总是发生错误,后来发现当没找到路线时,赋值为None,而一路上行的索引也为0,就导致了冲突,后来把None改为-1就解决了问题,通过这次课设,更加了解了邻接表储存图的操作,还学会了文件读取和写入的操作,通过模块化,把主页面和功能分开,当时读写文件的时候,中文字符一直乱码,查了一下把txt文件的编码改了一下,总之乱码一般就是编码不一致导致的,不管遇到问题还是bug,其实自己都可以慢慢解决,就是时间问题,不能急躁,这次课设,从中受益匪浅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值