天津地铁最短换乘项目
一、任务:
实现一个帮助进行地铁出行路线规划的命令行程序。
GitHub项目地址:
https://github.com/ldjkwx/TianJing-Subway
二、项目分析与规划
1.程序的模块,依赖关系以及估计开发所需的时间:
程序由Java语言编写,利用Dijkstra算法实现路径的选择,模块间的依赖关系如下图:
估计开发时间如下图:
PSP 2.1 | Personal Software Process Stages | Time |
---|---|---|
Planning | 计划 | |
· Estimate | · 估计这个任务需要多少时间 | 18 |
Development | 开发 | |
· Analysis | · 需求分析 (包括学习新技术) | 1 |
· Design Spec | · 生成设计文档 | 1 |
· Design Review | · 设计复审 (和同事审核设计文档) | 1 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 1 |
· Design | · 具体设计 | 1 |
· Coding | · 具体编码 | 5 |
· Code Review | · 代码复审 | 2 |
· Test | · 测试(自我测试,修改代码,提交修改) | 2 |
Reporting | 报告 | |
· Test Report | · 测试报告 | 2 |
· Size Measurement | · 计算工作量 | 1 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 1 |
合计 | 18 |
2.实际花费时间如下图:
PSP 2.1 | Personal Software Process Stages | Time |
---|---|---|
Planning | 计划 | |
· Estimate | · 估计这个任务需要多少时间 | 20 |
Development | 开发 | |
· Analysis | · 需求分析 (包括学习新技术) | 1 |
· Design Spec | · 生成设计文档 | 1 |
· Design Review | · 设计复审 (和同事审核设计文档) | 1 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 1 |
· Design | · 具体设计 | 1 |
· Coding | · 具体编码 | 8 |
· Code Review | · 代码复审 | 2 |
· Test | · 测试(自我测试,修改代码,提交修改) | 2 |
Reporting | 报告 | |
· Test Report | · 测试报告 | 2 |
· Size Measurement | · 计算工作量 | 1 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 1 |
合计 | 21 |
3.计算模块接口的设计与实现过程:
地铁数据的读取:
在读取了文件中的数据后,首先以 ”: “ 作为分隔,将每一行的数据分为三部分,第一部分为每条地铁的标号,第二部分为每条地铁的名称,第三部分为每条地铁的站点信息。
1:1号线:刘园,西横堤,果酒厂,本溪路,勤俭道,洪湖里,西站,西北角,西南角,二纬路,海光寺,鞍山道,营口道,小白楼,下瓦房,南楼,土城,陈塘庄,复兴门,华山里,财经大学,双林,李楼 2:2号线:曹庄,卞兴,芥园西道,咸阳路,长虹公园,广开四马路,西南角,鼓楼,东南角,建国道,天津站,远洋国际中心,顺驰桥,靖江路,翠阜新村,屿东城,登州路,国山路,空港经济区,滨海国际机场 3:3号线:小淀,丰产河,华北集团,天士力,宜兴埠,张兴庄,铁东路,北站,中山路,金狮桥,天津站,津湾广场,和平路,营口道,西康路,吴家窑,天塔,周邓纪念馆,红旗南路,王顶堤,华苑,大学城,高新区,学府工业区,杨伍庄,南站 5:5号线:北辰科技园北,丹河北道,北辰道,职业大学,淮河道,辽河北道,宜兴埠北,张兴庄,志成路,思源道,建昌道,金钟河大桥,月牙河,幸福公园,靖江路,成林道,津塘路,直沽,下瓦房,西南楼,文化中心,天津宾馆,肿瘤医院,体育中心,凌宾路,昌凌路,中医一附院,李七庄南 6:6号线:南孙庄,南何庄,大毕庄,金钟街,徐庄子,金钟河大桥,民权门,北宁公园,北站,新开河,外院附中,天泰路,北运河,北竹林,西站,复兴路,人民医院,长虹公园,宜宾道,鞍山西道,天拖,一中心医院,红旗南路,迎风道,南翠屏,水上公园东路,肿瘤医院,天津宾馆,文化中心,乐园道,尖山路,黑牛城道,梅江道,左江道,梅江公园,梅江会展中心,解放南路,洞庭路,梅林路 ................
代码中所包括的类与函数:
Map类: 地图,负责站点解析和路径计算。
程序将识别所有的转乘站点,作为一个结点,这样可以避免在计算最短路径过程中,将所有站点的距离都计算一遍,并且以map的形式记录其编号和线路总长度在这里。 为了方便后续的路径计算,我们以距离为模拟将每个站点计算出其编号,公式为(地铁线路标号*1000 + 当条地铁线第几个站点 +1)。 同时,在计算最短路径的同时,要保存每个结点最后被更新前的上一个结点,这样可以方便我们后续输出其完整路径。
包括的函数:
public void loadLineFile(String strSubwayFileName) {}//加载地铁线路数据 void parseSubwayStationsData() {}//地铁数据处理 void parseSubwayLineData(String strSubwayLine) {}//地铁路线处理,包括对地铁线的划分处理,以及对中转站的判定。 Path Dijkstra(String strStartStationName, String strEndStationName){}//利用迪杰斯特拉最短路径算法求最短的地铁路线。 void printPath(String start,String end, String strOutFileName){}//打印一个路径 String formatPath(String start,String end) {}//将读取的地铁站数据返回 Vector<String> stationsInLine(Station stationStart, Station stationEnd) {}//同时在打印两个中间转站点之间的站点时,当两个站点的id差值为正的时候,就将step设置为正1,每次加1,并通过得到的编号输出站点名;同样,当两个站点的id 差值为负的时候,就将step设置为-1即可,最后,通过计算出的地铁线路编号和地铁名称的map,输出地铁名称以及地铁线路的信息,最后将其输入到txt文件中去。 void printLineInfo(String LineName, String strOutFile) {}//获取特定地铁线路数据 int getLineNumber(int nStationId){}//获取subway.txt中第一列的地铁号数 int getLineNumber(String strLine){}//获取subway.txt中第二列的地铁线 int getLineNumber(Station S1, Station S2) {}//获取两个站点之间所需的地铁线路 int getStationsDistance(Station S1, Station S2) {}//获取两个站点之间距离的站数 void toFile(String strContent, String strOutFile) {}//将地铁站点输入到文件
Path类:路径,距离和经过的中转站列表。
Station类:站点,保存站点名称和ID。
subway类:定义main()实现程序的运行。
4.改进算法的性能所花费的时间。
对于算法的性能我们并没有进行过多的关注,但是在选择算法时,还是选的迪杰斯特拉算法求的最短路径,因为该算法不仅容易理解,而且网上有很多已经实现该算法的源代码,所以选择了该算法。
对于迪杰斯特拉算法:
a.初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例 如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
b.从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。
c.更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
d.重复步骤(b)和(c),直到遍历完所有顶点。
三、 程序测试&调试
- 1.-map 后没有参数信息
java subway -b 北宁公园 顺驰桥 -map`
- 2.缺少输出文件信息
`java subway -b 北宁公园 顺驰桥 -map subway.txt -o`
- 3.缺少起点或终点信息
`java subway -b 北宁公园 -map subway.txt -o routine`
- 4.查询的地铁线路不存在
`java subway -a 8号线 -map subway.txt -o station.txt`
- 5.查询的地铁起点或终点站不存在
`java subway -b 北宁公园 顺驰桥 -map subway.txt -o routine.txt`
- 6.查询指定地铁线路并输出到station.txt
`java subway -a 9号线 -map subway.txt -o station.txt`
输出的station.txt文件内容:
地铁:9号线 天津站 大王庄 十一经路 直沽 东兴路 中山门 一号桥 二号桥 张贵庄 新立 东丽开发区 小东庄 军粮城 钢管公司 胡家园 塘沽 泰达 市民广场 太湖路 会展中心 东海路
- 7.查询的起点*终点*在同一条地铁线上
`java subway -b 张兴庄 肿瘤医院 -map subway.txt -o routine.txt`
输出的station.txt文件内容:
地铁:3号线 丰产河 华北集团 天士力 宜兴埠 张兴庄 铁东路 北站 中山路 金狮桥 天津站 津湾广场 和平路 营口道 西康路 吴家窑 天塔 周邓纪念馆 红旗南路 王顶堤 华苑 大学城
- 8.查询的起点终点不在同一条地铁线上
`java subway -b 张兴庄 肿瘤医院 -map subway.txt -o routine.txt`
输出的station.txt文件内容:
地铁:3号线 铁东路 北站 中山路 金狮桥 天津站 地铁:9号线 大王庄 十一经路 直沽 地铁:5号线 下瓦房 西南楼 文化中心 天津宾馆 肿瘤医院
四、总结
通过这次结对项目让我对于数据结构+算法=程序有了更加深刻的认识
本次程序的难点主要在对于数据结构的设计,
一是数据的处理:读取.txt文件需要处理地铁线和站点的之间的站点和所属线路、相邻站点之间的约束关系,代码量和复杂度就相应的增大了不少。
二是路线的设计,为了便于处理路线间与路线内的站点之间的关系,通过设计LineNumber,进一步简化节点边的权重设计。使得LineNumber可以承载线路以及站点间的距离多重信息,使得使用Dijkstra算法更加便捷。
三是算法的设计:Dijkstra算法虽然原理简单,但是对于数据结构的实现和使用有一定的要求。需要妥善的处理搜索过的站点以及添加路径的选择。以及最终路径通过保存到栈中,依次输出。
同时,通过结对编程,我认为软件以及程序的开发。需要程序的模块间进一步的实现高内聚低耦合,这样才能产出复用性强,质量有保证的程序;同时结对编程能够帮助组队人互相提高,并且保证产出代码和软件的质量; 通过这次的学习,也让我和队友对于软件工程有了新的领悟。