地铁出行规划
地铁出行规划
代码链接
https://github.com/hkymygithub/-.git
功能描述
本程序可以根据输入的地铁线路来获得通过最少站点数到达目的地的路径。
命令行运行格式如下:
1.获得单条线路所有站点
java Subway -map 地铁线路文件.txt -a 线路名称 -o 输出文件.txt
2.获得最短线路
java Subway -map 地铁线路文件.txt -b 起始站点 目的站点 -o 输出文件.txt
线路存储格式
线路以文本文件形式存放,具体格式如下:
线路1 站点1 能否换乘
线路1 站点2 能否换乘
线路2 站点1 能否换乘
线路2 站点2 能否换乘
……
其中,一个站点若不能换乘,“能否换乘” 为否;若能换乘,“能否换乘” 为换乘线路,如果线路不止一条则用“,”隔开。
具体示例:
一号线 苹果园 否
一号线 古城 否
一号线 八角游乐园 否
一号线 八宝山 否
一号线 玉泉路 否
一号线 五棵松 否
一号线 万寿路 否
一号线 公主坟 十号线
一号线 军事博物馆 九号线
二号线 西直门 十三号线,四号线
二号线 车公庄 六号线
二号线 阜成门 否
二号线 复兴门 一号线
二号线 长椿街 否
代码设计
存储模式
程序利用Subway、Route、Station三个类来构建和存储线路
Subway类结构
public class Subway { private static final int INFINITY=1000;//站点间最大距离,用于Dijkstra算法 private List<Route> subroute;//包含的线路Route实例 private int rnumber;//包含线路条数 private Set<String> stationset;//用于除去重复站点 private Map<String,Integer> stationmap;//用于建立站点和站点序号的对应关系 private Map<Integer,String> stationmapch;//用于建立站点序号和站点的对应关系 private int[][] graph;//站点的距离矩阵,用于Dijkstra算法 private int[] path;//根据Dijkstra算法获得的最短路径 }
Route类结构
public class Route { private String rname;//线路名称 private List<Station> stationinfor;//线路包含的Station实例 private int snumber;//包含的站点数 }
Station结构
public class Station { private String route;//所属线路名称 private String sname;//站点名称 private String[] transfer;//能换乘的线路 }
核心算法:Dijkstra算法
private int findMinDist(int[] dist,boolean[] collected) { int minv=0; int v=0; int mindist=Subway.INFINITY; for(v=0;v<this.graph.length;v++) { if(collected[v]==false&&dist[v]<mindist) { mindist=dist[v]; minv=v; } } if(mindist<Subway.INFINITY) return minv; else return -1; } public boolean dijkstra(String firststation) {//Dijkstra算法 int v,w; int[] dist=new int[this.graph.length]; this.path=new int[this.graph.length]; boolean[] collected=new boolean[this.graph.length]; Integer s=this.stationmap.get(firststation); if(s==null) return false; for(v=0;v<this.graph.length;v++) { dist[v]=this.graph[s][v]; if(dist[v]<Subway.INFINITY) path[v]=s; else path[v]=-1; collected[v]=false; } dist[s]=0; collected[s]=true; while(true) { v=this.findMinDist(dist, collected); if(v==-1) break; collected[v]=true; for(w=0;w<this.graph.length;w++) { if(collected[w]==false&&this.graph[v][w]<Subway.INFINITY) { if(this.graph[v][w]<0) return false; if(dist[v]+this.graph[v][w]<dist[w]) { dist[w]=dist[v]+this.graph[v][w]; path[w]=v; } } } } return true; }
换乘判断
换乘判断依据:①起始站到下一站无需换乘,终点站与前一站无需换乘。②当前所在线路与下两站包含线路不同时需要换乘。例如:
从四道桥到苹果园,由于四道桥与金安桥之间的线路与金安桥到苹果园之间的线路不同所以要换乘。
从大望路到四惠东,由于大望路到四惠之间的线路包含在四惠与四惠东线路中,因此不需换乘。
具体代码:
private boolean inSameRoute(String route,Station station) {//判断当前所在线路到下一站的线路是否相同 if(station.getRoute().equals(route)) return true; //true就在同一线路不用转站,false就要转站 if(station.getTransfer()[0].equals("否")==false) { for(int i=0;i<station.getTransfer().length;i++) { if(station.getTransfer()[i].equals(route)) return true; } } return false; }
在需要换乘时,如果到下一个站点间路线有多条,为了使一次出行换乘次数尽量少,所以需要以递归方式查看之后站点的走向来判断本次需要转到的线路。
具体代码:
private String getChangeRoute(List<Station> linelist,String nowroute,int i) {//要转站时,判断要转去那条线 String route=null; if(linelist.get(i).getTransfer()[0].equals("否")) { route=linelist.get(i).getRoute(); } else { if(i==0) route=nowroute;//如果下一站为终点站,则返回当前线路 else route=this.getChangeRoute(linelist,this.getRouteBetweenTwo(linelist.get(i), linelist.get(i-1)).get(0), i-1); } return route; }
异常处理
1.线路不存在,处理方式:程序输出“线路不存在”并结束程序
2.起点站或终点站不存在,处理方式:程序输出“起点站或终点站不存在”并结束程序
3.起点终点相同,处理方式:程序输出“起点终点不能相同”并结束程序
4.缺少地铁线路图,处理方式:程序输出“缺少线路图”并结束程序
5.输入参数格式错误,处理方式:程序输出“命令格式有误”并结束程序
6.没有输出文件,处理方式:程序输出“缺少输出文件”并结束程序
测试样例
总结
本次作业的关键是利用dijkstra算法来获得最短路径,所以在保存站点信息时要适用于算法,在得到最短路径后还需判断站点间是否需要换乘,由于现实情况多种多样,所以这一部分较为复杂。在代码上,由于开始考虑不够充分所以导致代码看上去比较繁琐,所以还有较大的提升空间。