地铁最短路径问题

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语言面向过程的思路上,未能真正理解面向对象的编程思想,以后要继续努力。

 对于这次实验,我明白了我所掌握的知识还远远不够,以后要更加努力,扩充知识范围。










以上是关于地铁最短路径问题的主要内容,如果未能解决你的问题,请参考以下文章

地铁最短路径(代码部分)

地铁最短路径问题

地铁线路最短路径问题

地铁线路最短路径

魔都地铁降价了? 地铁方:“最短路径”缩短票价降1元

上海地铁悄悄降价了? 地铁方:“最短路径”缩短票价降1元