SubwayPlan
GitHub:https://github.com/wakerh1/subwayBJ
北京地铁图片:

地铁出行路线规划项目需求及实现概要:
1.设计一种文件格式用于存储地铁信息
2.设计启动程序并读取地铁信息文件的命令行
3.可以输出查询的具体地铁路线的所有途径地铁站点
4.能够告知用户两个站点之间的最短路线
5.进行代码复审
6.进行测试
7.进行性能检测
主要术语表:
| 中文名 | 英文 | 解释 |
| 线路 | Line | 地铁线路,线路上有很多的站点 |
| 站点 | Station | 地铁站点 |
主要模块介绍:
| 序号 | 模块名称 | 主要功能 |
对应java文件或方法类 |
| 1 | 主模块 | 流程控制、文件数据读入 | src/subwayMap/subway_0 |
| 2 | 核心算法模块 | 实现Dijkstra算法和最短路径算法 |
src/subwayMap/subway_0中的 方法类 dijkstraTravel shortestPath |
| 3 | 输出模块 | 输出站点与线路信息 | src/subwayMap/Main |
1.输出模块
- -b 后 输入线路名,输出该线路对应的所有站点
示例:
-b 请输入线路名 1号线
- -a后输入起始站和终点站,生成最短路径并生成:
示例:
-a 请输入起点: 苹果园 请输入终点: 白堆子 最短路径生成:
2.核心算法模块:实现Dijkstra算法
- 利用HashMap 存储全部的站点信息,并以站点名称为key
HashMap 存储全部的站点信息,并以站点名称为key
- 使用for循环遍历后使所有站结点都为为访问状态
- 定义flag遍历来控制循环开始
- 通过循环遍历找出站点中未被访问过,同时路径总站数最少的路线各点
具体代码如下:
private void dijkstraTravel(Station s){ Set<Station> set = map.keySet(); //for循环使所有站节点都为未访问状态 for (Station station : set) { station.visited = false; station.dist = Integer.MAX_VALUE; } s.dist = 0;//先令起点距离为0 boolean flag = true;//控制循环开始 while(flag){ Station v = null;//表示当前站节点 Station w;//表示当前站节点的邻接节点 //for循环找出站节点中未被访问 且距离(dist)最小的站节点 for (Station station : map.keySet()) { if(station.visited == true) continue; if(v == null || station.dist < v.dist) v = station; } //访问当前节点 v.visited = true; //遍历当前节点的邻接节点 List<Edge> list = map.get(v); for (int i = 0; i < list.size(); i++) { w = list.get(i).station; if(!w.visited){ int d = list.get(i).distance; //修改邻接节点的距离和路径 if(v.dist + d < w.dist){ w.dist = v.dist + d; w.path = v; } } } //遍历节点集 有未遍历的节点则while循环继续 Iterator<Station> iterator = map.keySet().iterator(); while(iterator.hasNext()){ if(!iterator.next().visited){ flag = true; break; } } if(!iterator.hasNext()) flag = false; } }
3.主模块
- 文件数据读入
//部分代码:
private void fileReader(){ File f = new File("mapdata/subwayInfo_bj.txt"); if(f.exists()){ try { FileReader out = new FileReader(f); BufferedReader br = new BufferedReader(out); String line = null;//用于按行读取文件 int nums = Integer.parseInt(br.readLine());//记录一共多少条地铁线
- 处理特殊情况(环路、起始站和终止站同站、不存在站名、不存在路线)
//1 始发站问题 if(j == 0){ head = s; } //2 终点站问题(环路则处理 非环路不处理) if(j == trackStationsNum-1 && nextDistance > 0){ //环路要在始发站 存储到达终点站的边信息 map.get(head).add(pre); //对终点站存储始发站的边信息 map.get(s).add(new Edge(head,trackName,nextDistance)); }
- 定义数据结构
private class Station{ String stationName; boolean visited; //以下两个变量用于迪杰斯特拉算法 int dist; Station path; String trackName; int SetTname=0; String pretrackname; public Station(String stationName) { super(); this.stationName = stationName; this.visited = false; this.dist = Integer.MAX_VALUE;//类似于无穷了 this.path = null; this.trackName = null; this.pretrackname = null; } }
private class Edge{ //String name; Station station; String lineName; int distance; public Edge(Station station, String lineName, int distance) { super(); this.station = station; this.lineName = lineName; this.distance = distance; } @Override public String toString() { return "Edge [station=" + station + ", lineName=" + lineName + ", distance=" + distance + "]"; } }
实现思路:
本次大作业我们要完成的主要任务有设计文件的存储格式、查询地铁线路和站点间最短路线问题。
首先对于站点信息的文件存储格式,可以使用xml格式或者json格式,如果使用json格式侧需要编写相应的json格式转换的代码,但是json格式的方便程度是比较高的。而xml格式则比较繁琐。
1.要查询地铁线路,可以建立一个线路(Line)的list,在Java中可以使用ArrayList,而每个线路又是一个站点(station)它的列表,那么只需要遍历线路列表找到查询的线路并输出就可以(但是这样性能上可能会差一些),也要记得处理异常情况——找不到查询线路的问题。
2.要得出两个站点之间的最短路径,那么迪杰斯特拉算法是一种不错的选择,广度优先遍历同样可行;对于广度优先遍历,只要明确一点,最先找到终点站的路线就是最短路线。这里的异常情况是——找不到要查询的站点。
本次大作业如果使用C/C++来实现的话,性能上会有一定的优势,但是本次大作业的结构与功能并不是很复杂,java语言也可以胜任;鉴于个人对C++、Json格式的练习较少,我打算使用Java语言来编写此次大作业。
以下是输入格式设计:
{
1号线 23
苹果园 1
古城 1
八角游乐园 1
八宝山 1
玉泉路 1
五棵松 1
万寿路 1
公主坟 1
军事博物馆 1
木樨路 1
南礼士路 1
复兴门 1
西单 1
天安门西 1
天安门东 1
王府井 1
东单 1
建国门 1
永安里 1
国贸 1
大望路 1
四惠 1
四惠东 -1
}
线路名后跟着线路总站点数,然后每条线路包含所有的站点名,每个站点名后跟着的1代表一站,计算最短路径
时采用的是对比路线所需要经过的站数是否最少。
测试分析:
1)功能测试
1.读入文件(已经在主模块中直接读取)
2.查询线路,参数为:-b 1号线
测试结果: -b 请输入线路名 1号线 苹果园 古城 八角游乐园 八宝山 玉泉路 五棵松 万寿路 公主坟 军事博物馆 木樨路 南礼士路 复兴门 西单 天安门西 天安门东 王府井 东单 建国门 永安里 显示路线成功
3.查询最短线路:
参数为-a 苹果园 白堆子(目前存在一些不足,个别乘坐线路的描述存在问题)
-a
请输入起点:
苹果园
请输入终点:
白堆子
最短路径生成:
乘1号线
苹果园
乘1号线
古城
乘1号线
八角游乐园
乘1号线
八宝山
乘1号线
玉泉路
乘1号线
五棵松
乘1号线
万寿路
乘1号线
公主坟
乘1号线
军事博物馆
乘9号线
白堆子
生成成功
2)异常情况处理测试:
1.起点与终点相同:-a 苹果园 苹果园
-a
请输入起点:
苹果园
请输入终点:
苹果园
最短路径生成:
起点与目的地重合
乘1号线
苹果园
生成成功
2.起点或终点不存在: -a 苹果园 钱塘江
-a 钱塘江 西直门
-a
请输入起点:
苹果园
请输入终点:
钱塘江
最短路径生成:
不存在的目的地
钱塘江
-a
请输入起点:
钱塘江
请输入终点:
西直门
最短路径生成:
不存在的起点
3.起点或终点不存在: -b 八十八号线
-b
请输入线路名
八十八号线
不存在该路线
参考文档:https://github.com/lihaibin921/subwayMap
修改部分:增加了输出在换乘点换乘的功能
参考文档中不含有输出单条路线所有站点功能
修改输出方式
对原始的数据结构进行了修改

浙公网安备 33010602011771号