北京地铁出行路线规划命令行程序 完成总结
GitHub:https://github.com/shysimon/my_subway
项目具体功能、使用方法以及算法思想,见上一篇博客:https://www.cnblogs.com/shysimon/p/11559850.html
各模块功能介绍
cn.edu.zucc.shy.model.Line:地铁线路类
cn.edu.zucc.shy.model.Station:地铁站类
cn.edu.zucc.shy.model.Edge:存储地铁站相邻地铁站的编号及所属线路
cn.edu.zucc.shy.model.NowAt:存储当前状态信息,在dijkstra算法中作为优先队列存储的数据结构单元
cn.edu.zucc.shy.manager.FindWay:存储地铁地图信息,查询后直接输出到输出流(文件或控制台,参数决定)
FindWay map = new FindWay(filepath); //输入文件路径,初始化寻路类 map.outWay(start, end, output); //输入起始站,目的站,输出流,直接在输出流输出找到的路 map.outLineInf(linename ,output); //输入线路名称,输出流,直接在输出流输出该线路
cn.edu.zucc.shy.manager.TxtLineReader:读取一行文件作为一条地铁线
ArrayListlines = TxtLineReader.read(filepath); //输入文件路径 将地铁线路文件转换成 地铁线路表
cn.edu.zucc.shy.manager.ArgsReader:处理程序输入参数以及异常处理
Pair> in = ArgsReader.argsReader(args); //输入命令行参数,返回处理之后的数据,并提供异常处理
cn.edu.zucc.shy.Main: 根据manager.ArgsReader返回的参数,使用manager.FindWay中对应的方法
subway:程序的入口,直接调用Main
寻路算法的具体实现
数据在程序运行过程中的存储
地铁线路信息文件为本程序的必备参数,读取 subway.txt 文件后调用 FindWay 的带参构造函数
使用 ArrayList
使用 ArrayList
使用 Map
使用 Map
for (int i = 0; i < lines.size(); i++) { mpLine.put(lines.get(i).getName(), i); for (int j = 0; j < lines.get(i).getStations().size(); j++) { String stationName = lines.get(i).getStations().get(j).getName(); if (mpStation.get(stationName) == null) { Vector> p = new Vector<>(); p.add(new Pair<>(i, j)); stations.add(new Pair<>(stationName, p)); mpStation.put(stationName, stations.size() - 1); } else { stations.get(mpStation.get(stationName)).getValue().add(new Pair<>(i, j)); } } }
使用 ArrayList
for (int i = 0; i < lines.size(); i++) { int u = mpStation.get(lines.get(i).getStations().get(0).getName()); for (int j = 1; j < lines.get(i).getStations().size(); j++) { int v = mpStation.get(lines.get(i).getStations().get(j).getName()); edges.get(u).add(new Edge(v, i)); edges.get(v).add(new Edge(u, i)); u = v; } }
输出对应地铁线路的所有站点信息
直接在 mpLine 找到对应的线路的下标,在lines中找到输出
寻找最短路的过程
先在 mpStation 中找到对应起点、终点的下标,在 stations 找到所有可能的初始状态(换成站可以选择多条线路),对于每一种初始状态,都跑一遍最短路,输出在长度最短的情况下换乘最少的情况。
输出路径以及换乘线路信息的方法是,使用优先队列优化的 dijkstra 算法中,每次进入新的节点,就将进入时的状态保存在当前站点下标位置的数组中,保存的状态包括前一个站点的下标,当前所在的线路下标。这样,在找到最短路之后,从终点反着找回去,即可得到完整最短路,以及换成线路的信息。
关键代码:
r = new StringBuilder(); int now = en, line = path[now].atLine; while (now != -1) { r.insert(0, " " + stations.get(now).getKey()); now = path[now].from; if (now == -1 || path[now].atLine != line) { int oldLine = line; if (now != -1) { r.insert(0, " " + stations.get(now).getKey()); line = path[now].atLine; } r.insert(0, "\n<" + lines.get(oldLine).getName() + ">"); } } output.write("从 "+start+" 到 "+end+" 共经过" + (minChange + 1) + "条线路," + (minLength + 1) + "个站点" + r);
输出效果如下:
从 苹果园 到 德茂 共经过6条线路,25个站点 <1号线> 苹果园 古城 八角游乐园 八宝山 玉泉路 五棵松 万寿路 公主坟 军事博物馆 <9号线> 军事博物馆 北京西站 <7号线> 北京西站 湾子 达官营 广安门内 菜市口 <4号线> 菜市口 陶然亭 北京南站 <14号线东段> 北京南站 永定门外 <8号线南段> 永定门外 木樨园 海户屯 大红门南 和义 东高地 火箭万源 五福堂 德茂