zoukankan      html  css  js  c++  java
  • 地铁结队开发(二)

    由一可知两条线之间可以用ID也就是数字去做加减,

    但是如果站多了,变成了2个以上,那就要标记换乘站了,虽然两条线的也有但是两条线只有1个点,而2条线以上的话就会有多了,

    并且甚至还会组成一个闭环,这样如果还是只用ID去计算的话未免有些力不从心了,所以再加一条换乘

    这样ID去计算一条线上的,遇到换线就进行换乘,然后再用ID去计算。这样的双重标记就很好了

    经查阅,有一个 Dijkstra(迪杰斯特拉)算法可以解决

    迪杰斯特拉算法:是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

    算法思想:(来自百度百科)

    按路径长度递增次序产生算法:
    把顶点集合V分成两组:
    (1)S:已求出的顶点的集合(初始时只含有源点V0)
    (2)V-S=T:尚未确定的顶点集合
    将T中顶点按递增的次序加入到S中,保证:
    (1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度
    (2)每个顶点对应一个距离值
    S中顶点:从V0到此顶点的长度
    T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度
    依据:可以证明V0到T中顶点Vk的,或是从V0到Vk的直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
    反证法可证)
    求最短路径步骤
    算法步骤如下:
    G={V,E}
    1. 初始时令 S={V0},T=V-S={其余顶点},T中顶点对应的距离值
    若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
    若不存在<V0,Vi>,d(V0,Vi)为∞
    2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中
    3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值
    重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------另外百度百科里有给了专门的各类编程语言的迪杰斯特拉算法,我们用java的
    Dijkstra(迪杰斯特拉)算法 —— Java实现
    //visit初始为0,防止回溯
    int visit[] = new int[n+1];
    //假设起点为src, 终点为dst, 图以二维矩阵的形式存储,若graph[i][j] == 0, 代表i,j不相连
    int Dijkstra(int src, int dst, int[][] graph){
        PriorityQueue<Node> pq = new PriorityQueue<Node>();
        //将起点加入pq
        pq.add(new Node(src, 0));
        while(pq.size()){
            Node t = pq.poll();
            //当前节点是终点,即可返回最短路径
            if(t.node == dst) return t.cost;
            //若当前节点已遍历过,跳过当前节点
            if(visit[t.node]) continue;
            //将当前节点标记成已遍历
            visit[t.node] = 1;
            for(int i = 0; i < n; i++){
                if(graph[t.node][i] && !visited[i]){
                    pq.add(new Node(i, t.cost + graph[t.node][i])); 
                }
            }
        }
        return -1
    }
    //定义一个存储节点和离起点相应距离的数据结构
    class Node implements Comparator<Node> {
        public int node;
        public int cost;
       
        public Node()
        {
        }
       
        public Node(int node, int cost)
        {
            this.node = node;
            this.cost = cost;
        }
       
        @Override
        public int compare(Node node1, Node node2)
        {
            if (node1.cost < node2.cost)
                return -1;
            if (node1.cost > node2.cost)
                return 1;
            return 0;
        }
    }
    View Code

    -----------------------------------------------------------------------------(我是一条华丽的分割线)---------------------------------------------------------------------------------------------

    OK,铺垫工作完成,接下来进入实际的地铁多线Java开发程序
     
    这里一共有3个java文件
     
    我创建的包名为:test1
     
    首先,建立一个Station类,其中存放我们的地铁线路的各个信息
     
    Station.java
    package test1;
      
    import java.util.HashMap;
    import java.util.LinkedHashSet;
    import java.util.Map;
      
     
    public class Station {
         
        private String name; //地铁站名称,假设具备唯一性
         
        public Station prev; //本站在lineNo线上面的前一个站
         
        public Station next; //本站在lineNo线上面的后一个站
         
        //本站到某一个目标站(key)所经过的所有站集合(value),保持前后顺序
        private Map<Station,LinkedHashSet<Station>> orderSetMap = new HashMap<Station,LinkedHashSet<Station>>();
         
        public Station (String name){
            this.name = name;
        }
      
        public String getName() {
            return name;
        }
      
        public void setName(String name) {
            this.name = name;
        }
         
        public LinkedHashSet<Station> getAllPassedStations(Station station) {
            if(orderSetMap.get(station) == null){
                LinkedHashSet<Station> set = new LinkedHashSet<Station>(); 
                set.add(this);
                orderSetMap.put(station, set);
            }
            return orderSetMap.get(station);
        }
      
        public Map<Station, LinkedHashSet<Station>> getOrderSetMap() {
            return orderSetMap;
        }
         
        @Override
        public boolean equals(Object obj) {
            if(this == obj){
                return true;
            } else if(obj instanceof Station){
                Station s = (Station) obj;
                if(s.getName().equals(this.getName())){
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
         
        @Override
        public int hashCode() {
            return this.getName().hashCode();
        }
    }
    View Code
    其次:录入data数据
     
    DataBuilder.java
    package test1;
     
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
     
    
    public class DataBuilder {
        
        public static List<Station> line1 = new ArrayList<Station>();//1号线
        public static List<Station> line2 = new ArrayList<Station>();//2号线
        public static List<Station> line3 = new ArrayList<Station>();//3号线
        public static List<Station> line10 = new ArrayList<Station>();//4号线
        public static List<Station> lineS1 = new ArrayList<Station>();//5号线
        public static List<Station> lineS8 = new ArrayList<Station>();//6号线
        public static Set<List<Station>> lineSet = new HashSet<List<Station>>();//所有线集合
        public static int totalStaion = 0;//总的站点数量
        static {        
            //1号线
            String line1Str = "上庄南、上庄、西王、时光街、长城桥、和平医院、烈士陵园、新百广场、解放广场、平安大街、北国商城、博物院、体育场、北宋、谈固、朝晖桥、白佛、留村、火炬广场、石家庄东、南村、洨河大道、西庄、东庄、会展中心、行政中心、园博园、天元湖、东上泽、东洋";
            String[] line1Arr = line1Str.split("、");
            for(String s : line1Arr){
                line1.add(new Station(s));
            }
            for(int i =0;i<line1.size();i++){
                if(i<line1.size()-1){
                    line1.get(i).next = line1.get(i+1);
                    line1.get(i+1).prev = line1.get(i);
                }
            }
            
            /*******************************************************************************/
            //2号线
            String line2Str = "西古城、铁道大学、运河桥、蓝天圣木、长安公园、北国商城、大戏院、新世隆、东岗头、东三教、石家庄站、塔谈、塔谈南、南位、嘉华 ";
            String[] line2Arr = line2Str.split("、");
            for(String s : line2Arr){
                line2.add(new Station(s));
            }
            for(int i =0;i<line2.size();i++){
                if(i<line2.size()-1){
                    line2.get(i).next = line2.get(i+1);
                    line2.get(i+1).prev = line2.get(i);
                }
            }
            
            /*******************************************************************************/
            //3号线
            String line3Str = "西三庄、水上公园、柏林庄、市庄、市二中、新百广场、东里、槐安桥、西三教、石家庄站、东广场、孙村、塔冢、东王、南王、位同、三教堂、中仰陵、天山大街、南豆、韩通、北乐乡";
            String[] line3Arr = line3Str.split("、");
            for(String s : line3Arr){
                line3.add(new Station(s));
            }
            for(int i =0;i<line3.size();i++){
                if(i<line3.size()-1){
                    line3.get(i).next = line3.get(i+1);
                    line3.get(i+1).prev = line3.get(i);
                }
            }
            
            /*******************************************************************************/        
            //10号线
            String line10Str = "碧水蓝湾、东良厢、华医学院、法商学院、滨河街、京广东街、塔谈南、南栗、南焦客运站、赵卜口、南王、经济学院、东明商城、儿童医院、北宋、长安医院、建华市场、北翟营、十里铺、南高营、交通驾校";
            String[] line10Arr = line10Str.split("、");
            for(String s : line10Arr){
                line10.add(new Station(s));
            }
            for(int i =0;i<line10.size();i++){
                if(i<line10.size()-1){
                    line10.get(i).next = line10.get(i+1);
                    line10.get(i+1).prev = line10.get(i);
                }
            }
            
            /*******************************************************************************/        
            //s1号线
            String lineS1Str = "宫家庄、法商学院、东五里、碧海云天、审计厅、益友百货、和平医院、西焦、合作路、农科院、火车北站、市庄、军械学院、蓝天圣木、常青园、建华市场、南翟营
    " + 
                    "";
            String[] lineS1Arr = lineS1Str.split("、");
            for(String s : lineS1Arr){
                lineS1.add(new Station(s));
            }
            for(int i =0;i<lineS1.size();i++){
                if(i<lineS1.size()-1){
                    lineS1.get(i).next = lineS1.get(i+1);
                    lineS1.get(i+1).prev = lineS1.get(i);
                }
            }
            
            /*******************************************************************************/        
            //s8号线
            String lineS8Str = "东明商城、国际城、二十里铺、留村、星辰广场、北豆、南豆、东仰陵、北郗马、东佐";
            String[] lineS8Arr = lineS8Str.split("、");
            for(String s : lineS8Arr){
                lineS8.add(new Station(s));
            }
            for(int i =0;i<lineS8.size();i++){
                if(i<lineS8.size()-1){
                    lineS8.get(i).next = lineS8.get(i+1);
                    lineS8.get(i+1).prev = lineS8.get(i);
                }
            }
            
            lineSet.add(line1);
            lineSet.add(line2);
            lineSet.add(line3);
            lineSet.add(line10);
            lineSet.add(lineS1);
            lineSet.add(lineS8);
            totalStaion  = line1.size() + line2.size() + line3.size() + line10.size() + lineS1.size() + lineS8.size();
            System.out.println("总的站点数量:"+totalStaion);
        }
    }
    View Code

    最后,就是我们的最重要的查询方法(也就是Dijkstra)写入了

    Subway.java

    package test1;
     
    import java.util.ArrayList;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Scanner;
     
     
    
    public class Subway {
        
        private List<Station> outList = new ArrayList<Station>();//记录已经分析过的站点
        
        //计算从s1站到s2站的最短经过路径
        public void calculate(Station s1,Station s2){
            if(outList.size() == DataBuilder.totalStaion){
                System.out.println("找到目标站点:"+s2.getName()+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
                for(Station station : s1.getAllPassedStations(s2)){
                    System.out.print(station.getName()+"->");
                }
                return;
            }
            if(!outList.contains(s1)){
                outList.add(s1);
            }
            //如果起点站的OrderSetMap为空,则第一次用起点站的前后站点初始化之
            if(s1.getOrderSetMap().isEmpty()){
                List<Station> Linkedstations = getAllLinkedStations(s1);
                for(Station s : Linkedstations){
                    s1.getAllPassedStations(s).add(s);
                }
            }
            Station parent = getShortestPath(s1);//获取距离起点站s1最近的一个站(有多个的话,随意取一个)
            if(parent == s2){
                System.out.println("找到目标站点:"+s2+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
                for(Station station : s1.getAllPassedStations(s2)){
                    System.out.print(station.getName()+"->");
                }
                return;
            }
            for(Station child : getAllLinkedStations(parent)){
                if(outList.contains(child)){
                    continue;
                }
                int shortestPath = (s1.getAllPassedStations(parent).size()-1) + 1;//前面这个1表示计算路径需要去除自身站点,后面这个1表示增加了1站距离
                if(s1.getAllPassedStations(child).contains(child)){
                    //如果s1已经计算过到此child的经过距离,那么比较出最小的距离
                    if((s1.getAllPassedStations(child).size()-1) > shortestPath){
                        //重置S1到周围各站的最小路径
                        s1.getAllPassedStations(child).clear();
                        s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                        s1.getAllPassedStations(child).add(child);
                    }
                } else {
                    //如果s1还没有计算过到此child的经过距离
                    s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                    s1.getAllPassedStations(child).add(child);
                }
            }
            outList.add(parent);
            calculate(s1,s2);//重复计算,往外面站点扩展
        }
        
        //取参数station到各个站的最短距离,相隔1站,距离为1,依次类推
        private Station getShortestPath(Station station){
            int minPatn = Integer.MAX_VALUE;
            Station rets = null;
            for(Station s :station.getOrderSetMap().keySet()){
                if(outList.contains(s)){
                    continue;
                }
                LinkedHashSet<Station> set  = station.getAllPassedStations(s);//参数station到s所经过的所有站点的集合
                if(set.size() < minPatn){
                    minPatn = set.size();
                    rets = s;
                }
            }
            return rets;
        }
        
        //获取参数station直接相连的所有站,包括交叉线上面的站
        private List<Station> getAllLinkedStations(Station station){
            List<Station> linkedStaions = new ArrayList<Station>();
            for(List<Station> line : DataBuilder.lineSet){
                if(line.contains(station)){//如果某一条线包含了此站,注意由于重写了hashcode方法,只有name相同,即认为是同一个对象
                    Station s = line.get(line.indexOf(station));
                    if(s.prev != null){
                        linkedStaions.add(s.prev);
                    }
                    if(s.next != null){
                        linkedStaions.add(s.next);
                    }
                }
            }
            return linkedStaions;
        }
     
        /**
         * desc: How to use the method
         * author chaisson
         * since 2015-5-31
         * version 1.0
         */
        public static void main(String[] args) {
            long t1 = System.currentTimeMillis();
            Subway sw = new Subway();
             Scanner sc = new Scanner(System.in); 
             System.out.println("请输入起点站:"); 
             String s1 = sc.nextLine();
             System.out.println("请输入终点站:"); 
             String s2 = sc.nextLine(); 
            sw.calculate(new Station(s1), new Station(s2));
            long t2 = System.currentTimeMillis();
            System.out.println();
            System.out.println("耗时:"+(t2-t1)+"ms");
        }
    }
    View Code

    OK我们的程序到这里就完成了,下面是截图

  • 相关阅读:
    JDBC的使用流程
    typescript vscode /bin/sh: ts-node: command not found
    小程序打开app场景
    设置获取cookie,setCookie,getCookie
    解决IOS微信页面回退不刷新问题
    百度小程序添加编译
    百度小程序审核不通过,基础库问题
    Charles Mac 破解安装和证书安装成功抓包单个域名是unknown
    xhrFields实现跨域访问
    Mac上启动nginx报错:nginx: [emerg] bind() to 0.0.0.0:80 failed (48: Address already in use)
  • 原文地址:https://www.cnblogs.com/mitang0-0/p/11061381.html
Copyright © 2011-2022 走看看