地铁线路最短路径
地铁路线最短路径
项目介绍:
主要功能:

提供一副地铁线路图,计算指定两站之间最短(最少经过站数)乘车路线;输出指定地铁线路的所有站点。以北京地铁为例,地铁线路信息保存在data.txt中,格式如下:
地铁线路总数
线路名1 站名1 站名2 站名3 ...
线路名2 站名1 站名2 站名3 ...
线路名3 站名1 站名2 站名3 ......
需求分析:
1、能够为用户在短时间内罗列出最佳的路线。
2、能够显示列出路线所要经过的站点。
3、用户输入路线号显示该路线所有站点使得用户能够查看。
实现语言:
本次作业使用Java语言编写
实现算法:
针对本次任务使用Dijkstra算法,在无向图从一点到另一点,遍历路径的过程中若到集合中的点的距离变小则更新到该点的距离,直到到达所要求的点。
类职责划分(将相关类的功能进行描述):
| 类 | 职责 |
| Station | 站点信息 |
| Line | 线路信息 |
| Dijkstra | 计算最短路径 |
| main | 地铁线路的读取、存储和选择查询功能 |
核心代码(将所有类的代码标注并提交):
Station(存放站点)
public class Station { private String station_name; //站点名 private List<String> station_line=new ArrayList<String>(); //所在线路(换乘站有多条) private List<Station> near_stations=new ArrayList<Station>(); //与之相邻的站点 public String getStation_name() { return station_name; } public void setStation_name(String station_name) { this.station_name = station_name; } public List<String> getStation_line() { return station_line; } public void setStation_line(List<String> station_line) { this.station_line = station_line; } public List<Station> getNear_stations() { return near_stations; } public void setNear_stations(List<Station> near_stations) { this.near_stations = near_stations; } }
Line(存放线路)
public class Line { private Station line_start; //线路起始站 private Station line_end; //线路终点站 private int distance; //距离 private Station front_station; //到达该站的最短路径中的上一站 private String line_name; //路线名称 private int line_change; //标记从上一站到该站是否有换乘,0为无换乘,1为需换乘 private List<Station> stations=new ArrayList<Station>();//记录站点 public List<Station> getStations() { return stations; } public void setStations(List<Station> stations) { this.stations = stations; } public Station getLine_start() { return line_start; } public void setLine_start(Station line_start) { this.line_start = line_start; } public Station getLine_end() { return line_end; } public void setLine_end(Station line_end) { this.line_end = line_end; } public int getDistance() { return distance; } public void setDistance(int distance) { this.distance = distance; } public Station getFront_station() { return front_station; } public void setFront_station(Station front_station) { this.front_station = front_station; } public String getLine_name() { return line_name; } public void setLine_name(String line_name) { this.line_name = line_name; } public int getLine_change() { return line_change; } public void setLine_change(int line_change) { this.line_change = line_change; } }
Subway(包含文件读取、存储和计算最短路径)
public class subway { public static void main(String[] args) throws IOException { public static LinkedHashSet<List<Station>> lineSet = new LinkedHashSet<List<Station>>(); //线路集合 System.out.print("请输入地铁路线文档路径:"); //D:\programdistg\java file\eclipse-wokespace\shortest_path\src\地铁线路信息.txt Scanner path=new Scanner(System.in); File file=new File(path.nextLine());//读取地铁路线文件 if(!file.exists()) throw new FileNotFoundException("文件路径有误"); Line lines=new Line(); Station stations=new Station(); BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//规定字符集以免出现乱码 String content=""; content=br.readLine(); int linenum=Integer.parseInt(content); for(int i=0;i<linenum;i++) { //循环往lineSet中添加line content=br.readLine(); List<Station> line=new ArrayList<Station>(); String[] splits=content.split(" "); String linename=splits[0]; for(int j=1;j<splits.length;j++) { //循环往line中添加station int flag=0; for(List<Station> l:lineSet) { //处理换乘站 for(int k=0;k<l.size();k++) { if(l.get(k).getName().equals(splits[j])) { List<String> newline=l.get(k).getLine(); newline.add(linename); l.get(k).setLine(newline); line.add(l.get(k)); flag=1; break; } } if(flag==1) break; } if(j==splits.length-1&&splits[j].equals(splits[1])) { //处理环线 line.get(0).getLinkStations().add(line.get(line.size()-1)); line.get(line.size()-1).getLinkStations().add(line.get(0)); flag=1; } if(flag==0) line.add(new Station(splits[j],linename)); } for(int j=0;j<line.size();j++) { //初始化每个车站相邻的车站 List<Station> newlinkStations=line.get(j).getLinkStations(); if(j==0) { newlinkStations.add(line.get(j+1)); line.get(j).setNear_stations(newlinkStations); } else if(j==line.size()-1) { newlinkStations.add(line.get(j-1)); line.get(j).setNear_stations(newlinkStations); } else { newlinkStations.add(line.get(j+1)); newlinkStations.add(line.get(j-1)); line.get(j).setNear_stations(newlinkStations); } } lineSet.add(line); } br.close(); System.out.print("选择要查询的类别 1、查询线路2、查询最短路径"); int choice=path.nextInt(); if(choice==1) { sysytem.out.print("请输入要查询的路线"); String line_name=path.next(); int flag=1; for(Line line:lines) { if(line.getLine_name().equals(line_name)) { System.out.print(lines.getStations().toString());//根据所存的数组直接输出 flag=0; break; } } if(flag==1) { System.out.print("线路名输入有误"); } } else if(choice==2) System.out.print("请输入起始站:"); String start_stationt_station_name=path.next(); System.out.print("请输入终点站:"); String line_end_station_name=path.next(); Station start_stationt_station = new Station(); Station line_end_station = new Station(); for(Station station:stations) { if(station.getStation_name().equals(start_stationt_station_name)) { start_stationt_station=station; } if(station.getStation_name().equals(line_end_station_name)) line_end_station=station; } ArrayList<Station> shortestPath=new ArrayList<Station>(); showPath(line_end_station,shortestPath); String changeLine=getSameLine(shortestPath.get(0),shortestPath.get(1)); for(int i=0;i<shortestPath.size();i++) { if(i>=2) { if(!getSameLine(shortestPath.get(i),shortestPath.get(i-1)).equals(changeLine)) { changeLine=getSameLine(shortestPath.get(i),shortestPath.get(i-1)); System.out.print(" ------->换乘 "+changeLine); } } System.out.println(shortestPath.get(i).getStation_name()+" "); } } else { System.out.print("输入有误,请重试"); } public static Dijkstra(Station start_station, Station end_station) { //dijkstra算法计算最短路径 private static List<Station> analysisList = new ArrayList<>(); //已经分析过的站点 private static HashMap<Station,Line> LineMap = new HashMap<>(); //结果集 private static Station getNextStation() { //获取下一个需要分析的站点 int dist=999999; Station rets = null; Set<Station> stations = LineMap.keySet(); for (Station station : stations) { if (analysisList.contains(station)) { continue; } Line Line = LineMap.get(station); if (Line.getDistance() < dist) { dist = Line.getDistance(); rets = Line.getline_end(); } } for(List<Station> l:DataBuilder.lineSet) { //构造结果集 for(int k=0;k<l.size();k++) { Line Line = new Line(); Line.setstart_station(start_station); Line.setline_end(l.get(k)); Line.setDistance(999999); Line.setLine_change(0); LineMap.put(l.get(k), Line); } } for(Station s:start_station.getLinkStations()) { //初始化结果集 LineMap.get(s).setDistance(1); LineMap.get(s).setPassStations(start_station); List<String> samelines=getSameLine(start_station.getLine(),s.getLine()); LineMap.get(s).setLine(samelines.get(0)); } LineMap.get(start_station).setDistance(0); analysisList.add(start_station); Station nextstation = getNextStation(); //计算下一个需要分析的站点 while(nextstation!=null) { //循环计算每一个站点的最短路径 for(Station s:nextstation.getnear_stations()) { if(LineMap.get(nextstation).getDistance()+1<LineMap.get(s).getDistance()) { //更新最短路径 LineMap.get(s).setDistance(LineMap.get(nextstation).getDistance()+1); LineMap.get(s).setPassStations(nextstation); List<String> samelines=getSameLine(nextstation.getLine(),s.getLine()); if(!samelines.contains(LineMap.get(nextstation).getLine())) { //需要换乘 LineMap.get(s).setLine(samelines.get(0)); LineMap.get(s).setLinechange(1); } else { LineMap.get(s).setLine(LineMap.get(nextstation).getLine()); } } } analysisList.add(nextstation); nextstation = getNextStation(); } int flag=1; for (List<Station> l:DataBuilder.lineSet) { flag=1; for(Station s :l) { if(!s.getLine().contains(linename)) flag=0; } if(flag==1) return l; } return null; } return LineMap.get(line_end); } }
测试用例(将输入输出结果截图提交):
1、测试第一个线路查询功能:

2、测试非换乘站点到非换乘站点

3、测试换乘站点到换乘站点

总结
首先是对于这次交作业的方式——上传博客感到很新颖,第一次写博客真的不太会。
其次是对于这次作业计算地铁地铁线路最短路径,让我对Dijkstra算法有了更深的了解,本次Dijkstra算法主要参考thankkk的博客。
另外在输出格式上开始也想想thankkk一样使用命令行但不太会用,便借鉴了suppersam的运行方式。
GitHub地址:https://github.com/ChasenSi/Subway

浙公网安备 33010602011771号