一、问题描述

公交线路图

设计一个控制台程序,使用图数据结构和算法,模拟城市公交系统,程序中保存了城市的公交线路和公交站点信息。开始运行时,输出菜单,供用户选择,具体实现的功能如下:
1、创建公交线路图
2、查询公交线路和站点信息
(1)查询公交线路
(2)查询站点信息
3、查询两站点之间的路线,找到至多换乘1次的路线,并输出结果。
4、附加文件存储功能,即站点消息、公交线路信息等数据不得写入程序中,要求保存在文件中。
(1)设计公交线路所需的存储结构,将文件中的数据读入内存。
(2)提供用户操作的菜单和界面实现添加、删除、修改公交、站点、线路信息。
(3)将修改后的信息保存回文件。

二、设计

(一)设计思想

1.存储结构

首先用多个文件存储数据保存站点信息将文件中的数据读入内存,建立图的存储结构。例如:在文件station.txt中保存站点信息:

在文件buses.txt中保存公交信息数组(格式为:公交编号 公交车号 起始站编号 终点站编号):

在文件名routes.txt中保存线路信息,(格式为:线路编号 站点编号 站点编号 距离):

(1)图的存储

当保存图结构时,既要保存顶点信息,也要保存边。图用数组来存储。用一维数组来保存顶点的集合,使用二维数组来保存边的集合。

(2)公交路线图

公交路线图可以看作是一个带权的有向图,使用邻接表来保存,所有站点即为图的顶点;当两个站点之间设有公交时,表示两个顶点相连,为一条边;两个站点之间的距离,即为边的权值。
在model.h文件中定义结构体:
1.定义结构体Bus代表一个公交车线路:

         typedef struct Bus {char Name[40];      //公交名int Start;     //起点int End;     //终点
}Bus;

2.定义结构体Station代表一个站点:

     typedef struct Station {char StationName[40];    //站点名
struct Route* Routes;        //从该站点出发的所有下行路线的链域
}Station;

3.定义结构体Route代表公交线路中的一个路段(邻接表结点):

    typedef struct Route {int IndexOfStation;        //指向的站点索引号int IndexOfBus;           //公交索引号int Distance;            //两站之间的公路距离struct Route* Next;      //起始站点相同的,下一条下行路线
}Route;

4.定义结构体BusMap存储整个公交地图信息:

     typedef struct BusMap {Bus* Buses;          //公交线路数组Station* Stations;  //站点数组int Station_Num;  //站点数int Bus_Num;       //公交线路数int Route_Num;
}BusMap;

2.主要功能的设计实现

首先是对问题功能的的划分:
为了存取方便,我们将线路信息,公交信息,站点信息等数据存入txt文件中,再利用数据存取将文本文件中的数据导入程序中。其中要求数据都储存在txt.文件中,使用一下语句实现文件的读写:

ifstream infile;infile.open("_Database\\stations.txt");if (!infile.is_open()) {cout << "stations.txt文件打开失败" << endl;exit(0);}while (!infile.eof()) {infile.getline(str1, 100);if (strcmp(str1, "") == 0)break;split_stations(str1, index, str2);AddStation(g_sMap, str2);}infile.close();

另外,设置文件写入方式为覆盖写入以保存修改信息:

ofstream outfile;   //打开文件,设置写入方式为覆盖写入outfile.open("_Database\\stations.txt", ios::ate);if (!outfile) {cout << "stations.txt文件打开失败!" << endl;exit(0);}for (int i = 0; i < g_sMap.Station_Num; i++)outfile << i << " " << g_sMap.Stations[i].StationName << "\n";outfile.close();

(二)设计表示

函数之间的调用关系图如下:

三、调试报告

经过对题目问题的深入分析,首先发现函数之间的调用较为复杂,使用流程图对函数之间的关系作出一个简单的梳理。这里我使用了多文件编程便于划分各个模块的功能,首先创建main.cpp文件作为程序的入口;menu.cpp用于声明和实现功能菜单;map.cpp用于声明和实现站点图的相关功能。其次是数据结构设计,公交线路图可以看作是一个带权的有向图,使用邻接表来保存,所有站点即为图的顶点,当两个站点之间有公交线路时,表示两个顶点相连,为一条边,两个站点之间的距离为边的权值。在实际的调试过程中,并没有涉及到复杂的算法,只是在寻找所有站点信息时,使用函数Stretch_Bus进行排序;另外,在对公交线路图的初始化的时候,新增函数split来添加站点、公交、线路信息。

四、系统环境(源代码和运行结果)

(一)创建公交线路图、打印菜单

1.源代码:

  void Initial() {char str1[100], str2[100];int index;g_sMap.Bus_Num = 0;g_sMap.Station_Num = 0;g_sMap.Route_Num = 0;g_sMap.Buses = NULL;g_sMap.Stations = NULL;cout << "调用txt文件初始化车站图..." << endl;ifstream infile;infile.open("_Database\\stations.txt");if (!infile.is_open()) {cout << "stations.txt文件打开失败" << endl;exit(0);}while (!infile.eof()) {infile.getline(str1, 100);if (strcmp(str1, "") == 0)break;split_stations(str1, index, str2);AddStation(g_sMap, str2);}infile.close();cout << "车站图初始化完毕!" << endl;
}

2.运行结果:
程序根据文件中的站点信息和线路信息创建公交线路图,实现线路的初始化,并且打印菜单显示不同的功能。

(二)查询公交线路

1.源代码:

void SearchOfBus(BusMap& g_sMap, char* Bus_Name) {int IndexOfBus = GetBusIndex(g_sMap, Bus_Name);int IndexOfStation1 = g_sMap.Buses[IndexOfBus].Start;cout << g_sMap.Stations[IndexOfStation1].StationName;Route* pRoute = g_sMap.Stations[IndexOfStation1].Routes;while (pRoute != NULL) {if (pRoute->IndexOfBus == IndexOfBus) {cout << "--->" << g_sMap.Stations[pRoute->IndexOfStation].StationName;cnt++;length += pRoute->Distance;pRoute = g_sMap.Stations[pRoute->IndexOfStation].Routes;continue;}pRoute = pRoute->Next;}
}

2.运行结果:
输入公交线路编号,系统通过公交编号查找到该路线途经的所有站点并输出

(三)查询站点信息

1.源代码:

      int FindRoute(BusMap& g_sMap, bool* Visited, int IndexOfStation1, int IndexOfStation2, int* nStation, int* nBus, int Index, int& length) {//寻路递归子函数,若寻到则输出路径//试图从IndexOfStation1出发寻找路径,则将该结点的访问值定为已访问Visited[IndexOfStation1] = true;Route* pRoute = g_sMap.Stations[IndexOfStation1].Routes;while (pRoute != NULL) {//若该点出发的某一路径对应的目标结点未曾走过,则试触if (Visited[pRoute->IndexOfStation] == false) {nBus[Index - 1] = pRoute->IndexOfBus;//将确定走入的结点压栈,更新路径nStation[Index++] = pRoute->IndexOfStation;length += pRoute->Distance;//要走入的结点是终点站if (pRoute->IndexOfStation == IndexOfStation2) //找到可达的路径输出else //要走入的结点不是终点站,则以走入的结点为起始点重新搜索FindRoute(g_sMap, Visited, pRoute->IndexOfStation, IndexOfStation2, nStation, nBus, Index, length);length -= pRoute->Distance;//将尝试过的到达站退栈Index--;}pRoute = pRoute->Next;}//将出发站重新定为未访问状态Visited[IndexOfStation1] = false;return 0;
}

2.运行结果:
输入站点名,系统通过站点名查找到所有经过该站点的公交线路并输出。

(四)查询两站点之间的路线

1.源代码:

   int SearchOfLIMITEDRoute(BusMap& g_sMap, char* Station1, char* Station2) {//申请存储访问表的布尔空间,并初始化bool* Visited = (bool*)malloc(sizeof(bool) * g_sMap.Station_Num);ClearVisited(Visited, g_sMap.Station_Num);//申请存储经过站点的数组空间,并将首结点定为起始站int* nStation = (int*)malloc(sizeof(int) * g_sMap.Station_Num);nStation[0] = IndexOfStation1;//申请存储换乘车辆的数组空间int* nBus = (int*)malloc(sizeof(int) * g_sMap.Bus_Num);int length = 0;Length = LENGTH_MAX; Times = 0; //初始化全局变量Length,TimesFindRoute(g_sMap, Visited, IndexOfStation1, IndexOfStation2, nStation, nBus, 1, length); //开始递归搜索if (Length < LENGTH_MAX) //递归搜索结束,输出最短路线free(Visited);free(nStation);return 0;
}

2.运行结果:
用户输入要查询的起点和终点,程序先判断两站点之间是否有一条路径(即两个站点之间是否连通)。若两个站点之间有路线:则找到所有最多换乘1次的路线,然后依次输出。
(1)提示共找到几条路线:从|起点站名|到|终点站名|共找到N条路线。
(2)循环依次输出每条路线,有路线编号和站点与公交信息。依次输出路线中经过的每一站,并在站点与站点之间输出两站点之间所坐的公交车名。
(3)输出两站点之间的最短路径,以及其换乘次数和路径长度。
(4)若两个站点之间没有可以找到的路线,则提示用户“两站之间没有公交线路!”。

(五)寻找至多换乘一次的路线

1.源代码:

   void SearchRoute_LessThanTwoBus(BusMap& g_sMap, char* Station_Name1, char* Station_Name2) {if (IndexOfStation1 != IndexOfStation2) {//理论上可找到至多不换乘的公交线路Route_Array[0] = g_sMap.Stations[IndexOfStation1].Routes;while (Route_Array[0] != NULL) {  //假设pR[cnt]->Index就是直达公交if (Route_Array[index]->IndexOfStation == IndexOfStation2) //找到到达站//寻找下一条直达公交,找到公交的下一条路线,并赋值到R_A[++index];Route* tpRoute = g_sMap.Stations[Route_Array[index]->IndexOfStation].Routes;while (tpRoute != NULL) {if (tpRoute->IndexOfBus == Route_Array[0]->IndexOfBus)break;tpRoute = tpRoute->Next;}Route_Array[0] = g_sMap.Stations[IndexOfStation1].Routes;//找到至多换乘一次的公交线路,在选乘的公交中屏蔽可不换乘到达的公交线路while (Route_Array[0] != NULL) {//将路线推至最低端,并逆推换乘一次的公交线路//从Route_Array[index]开始搜索换乘一次到达的线路while (index >= 0) {//寻找换乘一次的后一条公交,找不到则令index--,直至index < 0int HCindex = index + 1;Route_Array[index + 1] = g_sMap.Stations[Route_Array[index]->IndexOfStation].Routes;//寻找与之前乘坐公交不同的线路if (Route_Array[index + 1]->IndexOfBus == Route_Array[index]->IndexOfBus)Route_Array[index + 1] = Route_Array[index + 1]->Next;while (Route_Array[HCindex] != NULL) { //找到到达站Route* tpRoute = g_sMap.Stations[Route_Array[HCindex]->IndexOfStation].Routes;while (tpRoute != NULL) {if (tpRoute->IndexOfBus == Route_Array[HCindex]->IndexOfBus)break;tpRoute = tpRoute->Next;
}

2.运行结果:
系统根据输入的起点和终点,找到至多换乘一次的路线:
(1)首先输出不换乘的路线,若不存在,则提示“找不到不换乘可到达的路线!”。
(2)在寻找换乘一次的路线,并输出所有可能的路线,若不存在,则提示“找不到换乘一次可到达的路线!”

(六)站点管理

1.显示所有站点:

(1)源代码:

 void CoutStation(BusMap& g_sMap) {Route* pRoute;for (int i = 0; i < g_sMap.Station_Num; i++) {cout << g_sMap.Stations[i].StationName << endl;cout << "经过公交有:";pRoute = g_sMap.Stations[i].Routes;while (pRoute != NULL) {cout << "\t" << g_sMap.Buses[pRoute->IndexOfBus].Name;pRoute = pRoute->Next;}cout << endl;}
}

(2)运行结果:

2.添加站点:

(1)源代码:

int AddStation(BusMap& g_sMap, char* name) {//试图添加车站int i=GetStationIndex(g_sMap, name);if (i >= 0) {cout << "该站点已经存在,无需添加!" << endl;return i;}else {//确定添加车站g_sMap.Stations = (Station*)realloc(g_sMap.Stations, sizeof(Station) * (g_sMap.Station_Num + 1));//初始化车站结点Station* pStation = &g_sMap.Stations[g_sMap.Station_Num];strcpy(pStation->StationName, name);pStation->Routes = NULL;              //尚不知晓从此站点出发的第一个路线g_sMap.Station_Num++;//返回新添加的车站下标return g_sMap.Station_Num - 1;}
}

(2)运行结果:

3.修改站点名:

(1)源程序:

     case '2':cout << "请输入要更改的站点名:";cin >> str1;temp1 = GetStationIndex(g_sMap, str1);if (temp1 < 0)cout << "目标站点不存在" << endl;else {cout << "请输入要替换的站点名:";cin >> str2;for (temp2 = 0; temp2 < g_sMap.Station_Num; temp2++)if (strcmp(str2, g_sMap.Stations[temp2].StationName) == 0)break;if (temp2 >= g_sMap.Station_Num) {strcpy(g_sMap.Stations[temp1].StationName, str2);cout << "站点名" << "\"" << str1 << "\"" << "已成功更改为" << "\"" << str2 << "\"" << endl;}elsecout << "输入的新站点名不可与已有站点名相同" << endl;}break;

(2)运行结果:

4.删除站点:

(1)源程序:

    int DelStation(BusMap& g_sMap, char* Station_Name) {//试图删除车站int Station_Index;for (Station_Index = 0; Station_Index < g_sMap.Station_Num; Station_Index++)if (strcmp(g_sMap.Stations[Station_Index].StationName, Station_Name) == 0)break;if (Station_; i < DelBus_Num; i++)DelBusIndex >= g_sMap.Station_Num)return -1;//找到所有相关车辆信息int Bus_Array[Max_Bus_Num], DelBus_Num;All_Bus_gothrough_THE_Station(g_sMap, Bus_Array, DelBus_Num, Station_Index);//删除线路、车辆for (int i = 0(g_sMap, g_sMap.Buses[Bus_Array[i]].Name);//删除车站del_the_station(g_sMap, Station_Index);DeleteNoUesStation(g_sMap);return 0;
}

(2)运行结果:

(七)车辆管理、路线管理

1.源代码

  int DelStation(BusMap& g_sMap, char* Station_Name) {//试图删除车站int Station_Index;for (Station_Index = 0; Station_Index < g_sMap.Station_Num; Station_Index++)if (strcmp(g_sMap.Stations[Station_Index].StationName, Station_Name) == 0)break;if (Station_Index >= g_sMap.Station_Num)return -1;//找到所有相关车辆信息int Bus_Array[Max_Bus_Num], DelBus_Num;All_Bus_gothrough_THE_Station(g_sMap, Bus_Array, DelBus_Num, Station_Index);//删除线路、车辆for (int i = 0; i < DelBus_Num; i++)DelBus(g_sMap, g_sMap.Buses[Bus_Array[i]].Name);//删除车站del_the_station(g_sMap, Station_Index);DeleteNoUesStation(g_sMap);return 0;
}

2.运行结果:
对应实现显示所有车辆(路线),添加、修改、删除车辆(路线)的功能。


五、设计心得

   首先,复盘整个设计过程:1. 弄清楚程序所需要的实现的基本功能,设计模拟城市公交系统,也就是在文件中存储并调用公交站点信息,创建公交线路图,查询公交线路和站点信息,以及要求对站点以及公交线路词的修改、删除等功能。2. 其次是要设计针对特定功能的类,在本次设计中,在map.cpp文件中写入调用文件信息,添加、查找、删除公交线路信息的功能函数,model.h中定义站点信息和线路信息数据,另外在split.cpp中写入函数来实现从txt文件中修改公交线路信息,并且将修改后的信息保存回文件,在menu.cpp控制用户的操作显示界面。划分功能,保证每个类的功能清晰、简洁,在每个类内部实现的功能彼此联系。3. 对于程序具体实现,涉及到的算法问题其实并不复杂,主要是建立邻接表来储存线路图,实现对于图的顶点以及边的查找、删除、添加的工作。4. 程序的调试,针对测试出的问题不断进行改正,得到最终的代码,满足控制台的所有要求。在完成设计和调试后,开始着手实验报告,在不断地修改和改进中,对于整个题目有了更加深入的理解,最后也完成了所有的任务要求。通过本次数据结构的课程设计,一方面锻炼了分析问题、类设计的能力,另一方面对于图的存储结构有了更加深刻的认识。本次设计基本实现模拟城市公交系统的功能,但仍然还有许多改进的余地。比如程序的简化,优化界面设置,投入到实际应用中等等这些构想尚未实现。总体起来,是受益良多的,体会到了数据结构在实际开发应用中的重要意义,也进一步体会到了C++作为一门程序设计语言在较大项目管理中的优势,清晰的结构增减代码的易读性,也非常有助于提高系统的可拓展性,特别是本次的设计任务是有关生活实际的问题,“公交系统”大家在出行过程中都会接触,可是在课设中才真正了解它的工作原理,原来并不是那么的复杂,让我们在生活中运用所学专业知识从而深刻地体会到了书本知识具体化。

六、参考文献

[1] 数据结构(C语言版)/严蔚敏,吴伟民编著.—北京:清华大学出版社,2007
[2] C++语言程序设计/郑莉,董渊,何江舟编著.—4版.—北京:清华大学出版社,2010.7(2019.11重印)
[3] 数据结构实践教程(C语言版)/袁嵩主编.—武汉:华中科技大学出版社,2019.10

公交线路图-数据结构课程设计C++实现相关推荐

  1. 公交换乘系统c语言,数据结构课程设计报告(公交换乘).docx

    课 程 设 计 报 告 题目: 武昌地区公交查询与换乘推荐 课程名称: 数据结构课程设计 专业班级: 学 号: 姓 名: 指导教师: 报告日期: 计算机科学与技术学院 任 务 书 设计内容 掌握图.查 ...

  2. 数据结构课程设计 公交系统

    大家好! 这是我的第一篇文章,是将这学期的数据结构课设报告整理出来的.可能还有些小错误,还请多多指正. 数据结构课程设计<公交系统> 一.引言 (一)课题描述 (二)设计要求 二.总体设计 ...

  3. 数据结构课程设计——机票售卖系统(C++)

    引言 这学期最后的数据结构课程设计需要我们完成一个简单的小程序,我选择了一个机票售卖系统,实现了一些基本的功能:因为时间给的比较短,又赶在复习周补课,所以并没有什么突出的地方,我就在这里聊聊我的代码实 ...

  4. 数据结构课程设计---最长公共子串

    数据结构课程设计,由用户输入两个字符串串X和Y,再由用户输入一个任意的字符串Z,实现以下功能: ①如果字符串Z是字符串X的子串,则显示Z在X中的位置并记录,如果字符串Z是字符串Y的子串,则显示Z在Y中 ...

  5. 设树采用孩子兄弟表示法存放.用类c语言设计算法计算树的高度.,(数据结构课程设计分类题目.doc...

    (数据结构课程设计分类题目 线性表 顺序表: 1.设有一元素为整数的线性表L=(a1,a2,a3,-,an),存放在一维数组A[N]中,设计一个算法,以表中an作为参考元素,将该表分为左.右两部分,其 ...

  6. c语言数据结构五子棋实验报告,数据结构课程设计-五子棋

    数据结构课程设计-五子棋 姓 名: 学 院: 计算机与通信学院 班 级: 通信工程 101 班 指导老师: 目录一.需求分析 31.1 开发背景 .32.2 功能简介 .3二.系统设计 42.1 函数 ...

  7. 数据结构迷宫代码_数据结构课程设计——迷宫求解(二)

    前言 接上文的介绍,本文将主要介绍如何生成随机迷宫,在网上找到的资源也比较多,这里我选取了随机 Prim 算法生成迷宫,选择这个算法的理由如下: 算法思想简单,易于实现 生成的迷宫比较自然,不会出现明 ...

  8. c语言小数表达式运算课程设计,数据结构课程设计表达式计算.doc

    数据结构课程设计表达式计算 福建农林大学计算机与信息学院 计算机类 课程设计报告 课程名称:算法与数据结构课程设计题目:表达式计算姓 名:系:数学系专 业:数学与应用数学年 级:学 号:指导教师:宁正 ...

  9. 数据结构课程设计:顺序结构、动态链表结构下的一元多项式的加法、减法、乘法的实现...

    原来做的数据结构课程设计,今天整理资料时偶然发现了,自己留着没啥意思,共享一下吧,互相交流学习 要求 设有一元多项式Am(x)和Bn(x). Am(x)=A0+A1x1+A2x2+A3x3+- +Am ...

  10. c语言数据结构课程设计停车场管理系统,数据结构课程设计报告停车场管理系统...

    <数据结构课程设计报告停车场管理系统>由会员分享,可在线阅读,更多相关<数据结构课程设计报告停车场管理系统(8页珍藏版)>请在人人文库网上搜索. 1.数据结构课程设计报告系 别 ...

最新文章

  1. MonoDevelop 1.0 和 Mono 1.9(2.0 beta)发布了
  2. 网站关键词排名骤降的原因及解决办法
  3. spring二:装配bean(自动装配)
  4. display:table-cell自适应布局下连续单词字符换行
  5. SharePoint三个主要数据库
  6. 十、封装python3读写ini文件类
  7. editplus保存时自动创建备份文件设置关闭
  8. flask中蓝图的使用
  9. 甜品果汁饮品拍摄设计海报,美如蓬莱仙境!
  10. php验证注册不能纯数字,php写一个纯数字验证码教学
  11. 基于jQuery的判断iPad、iPhone、Android是横屏还是竖屏的代码
  12. 高亮显示不区分大小写的关键字——ASP
  13. php工商亮照添加代码,市场监管总局电子营业执照亮照系统上线
  14. 倒立摆小车matlab仿真,倒立摆系统的建模及Matlab仿真分析
  15. abb的knx的数据库下载方法_ABB智能家居KNX方案.doc
  16. MSP430F6638单片机复习笔记
  17. 亚马逊AWS EC212个月免费计划及连接问题
  18. SitePoint博客的3大变化
  19. 流式检测巨噬细胞方法
  20. 利用electron-vue技术实现一个邮箱客户端应用的项目总结

热门文章

  1. DDos攻击防御策略
  2. ElasticSearch学习总结2(基础查询)
  3. 摄影基础知识——光学变焦和数码变焦
  4. 中国正从法律入手编织公民信息保护网
  5. 思科无线服务器,Cisco统一无线网络TACACS+配置
  6. java bitset clean方法_BitSet实现原理及源码解析
  7. PS冷知识:PS隐藏功能中的组合键
  8. 人生感悟-是留丰碑还是墓碑
  9. 为什么闹钟设置了却不响_苹果手机为什么闹钟设置了却不响
  10. java 树什么意思是什么意思是什么意思_什么是红黑树?看完这篇你就明白了!...