地铁最短路径问题
Posted liunengwonanshen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了地铁最短路径问题相关的知识,希望对你有一定的参考价值。
项目介绍
主要功能
提供一副地铁线路图,计算指定两站之间最短(最少经过站数)乘车路线;输出指定地铁线路的所有站点。以北京地铁为例,地铁线路信息保存在data.txt中,格式如下:
地铁线路总数
线路名1 站名1 站名2 站名3 ...
线路名2 站名1 站名2 站名3 ...
线路名3 站名1 站名2 站名3 ...
实现语言
Java语言
实现算法
Dijstra算法 最短路径
思路
本题主要是利用Dijstra算法解决最短路径问题。
我参考了《Dijkstra算法在求解地铁站点最短路径问题中的关联矩阵生成方法》中求解地铁站最短线路问题的分析。
利用Java面向对象的特性,可以将站点设置为类,把与站点相关的线路,距离等设置为站点的属性,利用get/set方法进行调用或设置,可以有效的解决地铁的换乘以及距离问题,还可以避免遍历二维数组所造成的时间浪费。
代码思路方面参考https://www.cnblogs.com/xupppp/p/11663525.html
前提假设
1.从图论的角度看,地铁是无回路的,假设每两个站点之间的距离相等,比较路径长短相当于比较两站点之间的站点个数。
2.当最短路径不止一条时,只选择其中的一条。
代码路径
https://github.com/liunengwonanshen/ditiexianlu
类职责划分
函数 | 职责 |
Station.java | 主函数,负责调用其他java文件 |
Result.java | 存放输出相关的内容 |
Date.java | 将地铁信息导入数据结构中 |
Dijkstra.java | 调用Dijkstra算法,输出最短路径 |
Main.java | 主函数,负责调用其他java文件 |
核心代码
Station.java
public class Station { private String name;//站点名 private List<String> line=new ArrayList<>();//乘坐线路 private List<Station> Adjacentstations =new ArrayList<>();//相邻站点 //省略get/set方法 }
Result.java
public class Result { private Station star;//起始站 private Station end;//当前站点 private int distance;//距离起始站的距离 private Station previousstation;//前一站点 private String line;//所在线路 private int change;//时候换乘 //省略get/set方法 }
Date.java
//处理数据 public class Date { public static Set<List<Station>> lineSet=new LinkedHashSet<>();//存放所有站点 public Date() {}; public Date(String name) throws IOException{ File file=new File(name); Scanner input=new Scanner(file); InputStreamReader reader = new InputStreamReader( new FileInputStream(file),"UTF-8"); BufferedReader br = new BufferedReader(reader); String s; while((s=br.readLine())!=null) { //String s=br.readLine(); //System.out.println(s); List<Station> line=new ArrayList<>(); String[] collection=s.split(" "); String linename=collection[0]; //将站点放入lineSet //将站点放入line for(int i=1;i<collection.length;i++) { boolean flag=true; //有换乘 for(List<Station> l:lineSet) { for(int j=0;j<l.size();j++) { if(l.get(j).getName().equals(collection[i])) { List<String> newline=l.get(j).getLine(); newline.add(linename); l.get(j).setLine(newline); line.add(l.get(j)); flag=false; break; } } if(!flag) break; } //有环路 if(i==collection.length-1&&(collection[i].equals(collection[1]))) { //此时还没添加最后一站 line.get(0).getAdjacentstations().add(line.get(line.size()-1));//环路的起始站添加环路的终点站 line.get(line.size()-1).getAdjacentstations().add(line.get(0));//环路的终点站添加环路的起始站 flag=false; } //正常情况下 if(flag) line.add(new Station(collection[i],linename)); } for(int i=0;i<line.size();i++) { List<Station> LinkedStation=line.get(i).getAdjacentstations(); if(i==0) { LinkedStation.add(line.get(i+1)); line.get(i).setAdjacentstations(LinkedStation); } else if(i==line.size()-1) { LinkedStation.add(line.get(i-1)); line.get(i).setAdjacentstations(LinkedStation); } else { LinkedStation.add(line.get(i+1)); LinkedStation.add(line.get(i-1)); line.get(i).setAdjacentstations(LinkedStation); } } //s=br.readLine(); lineSet.add(line); //System.out.println(lineSet); } } }
Dijkstra.java
public class Dijkstra { private static List<Station> S=new ArrayList<>();//S 收集已经访问过的站点 private static Map<Station,Result> hashMap=new HashMap<>(); //计算最短路径 public static Result shortRoute(Station star,Station end) { //初始化Result for(List<Station> stations:Date.lineSet) { for(Station station: stations) { Result result=new Result(); result.setStar(star); result.setEnd(station); result.setDistance(999999); result.setChange(0); hashMap.put(station, result); } } //更新Result for(Station station: star.getAdjacentstations()) { hashMap.get(station).setDistance(1); hashMap.get(station).setPreviousstation(star); List<String> line=GetSameLine(star,station); hashMap.get(station).setLine(line.get(0)); } hashMap.get(star).setDistance(0); S.add(star); Station next=FindNextStation(); while(next!=null) { //将所有站点更新距离 for(Station s:next.getAdjacentstations()) { if(hashMap.get(next).getDistance()+1<hashMap.get(s).getDistance()) { hashMap.get(s).setDistance(hashMap.get(next).getDistance()+1); hashMap.get(s).setPreviousstation(next); List<String> sameline=GetSameLine(next,s); if(!sameline.contains(hashMap.get(next).getLine())) { hashMap.get(s).setLine(sameline.get(0)); hashMap.get(s).setChange(1); } else hashMap.get(s).setLine(hashMap.get(next).getLine()); } } S.add(next); //System.out.print(next.getName()+" "); next=FindNextStation(); } return hashMap.get(end); } //获得路径 public static void Path(Result end){ Stack<Station> stack=new Stack<>(); stack.push(end.getEnd()); Station s=end.getPreviousstation(); while(!s.equals(end.getStar())) { stack.push(s); //System.out.print(s.getName()); s=hashMap.get(s).getPreviousstation(); } stack.push(end.getStar()); int num=0; while(!stack.isEmpty()) { if(hashMap.get(stack.peek()).getChange()==1) { System.out.println("->换乘"+hashMap.get(stack.peek()).getLine()); System.out.println(stack.pop().getName()); } else System.out.println(stack.pop().getName()); num++; } System.out.println("一共经历了"+num+"站"); } //两个站点是否有相同的路线 public static List<String> GetSameLine(Station s1,Station s2){ List<String> sameline=new ArrayList<>(); for(String line1:s1.getLine()) for(String line2:s2.getLine()) if(line2.equals(line1)) sameline.add(line2); return sameline; } //寻找下一个站点 public static Station FindNextStation() { int min=999999; Station st=null; Set<Station> set=hashMap.keySet(); for(Station station:set) { if(S.contains(station)) continue; Result result=hashMap.get(station); if(result.getDistance()<min) { min=result.getDistance(); st=result.getEnd(); } } return st; } }
Main.java
public class main { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("请输入要查找的地铁文件:"); Scanner input=new Scanner(System.in); String filename=input.nextLine(); try { new Date(filename); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.print("请输入要查找的起始站点:"); input=new Scanner(System.in); String s1=input.next(); System.out.print("请输入要查找的终点站:"); input=new Scanner(System.in); String s2=input.next(); Station star=null; Station end=null; for(List<Station> l:Date.lineSet) for(Station s:l) { if(s1.equals(s.getName())) star=s; if(s2.equals(s.getName())) end=s; } if(star==null ) System.out.println("输入的起始站点不存在"); else if(end==null) System.out.println("输入的终点站不存在"); else { Result r=Dijkstra.shortRoute(star, end); Dijkstra.Path(r); } } }
测试用例
1.从天通苑到花园桥(单线站点到单线站点)
2.从奥林匹克公园到东直门(换乘站到换乘站)
3.从巴沟到长春桥(环线)
4.异常处理
总结
在这次编程中,我理解到仅仅是掌握算法是远远不够的,比如如何将文档中的地铁站点转化为能够使用的类或者数组,我刚开始完全没有头绪,也是在借鉴别人的分析思路才有了大致的方向。
对于Java语言,我的理解还远远不够。对于很多问题还是仅仅停留在C语言面向过程的思路上,未能真正理解面向对象的编程思想,以后要继续努力。
对于这次实验,我明白了我所掌握的知识还远远不够,以后要更加努力,扩充知识范围。
以上是关于地铁最短路径问题的主要内容,如果未能解决你的问题,请参考以下文章