北京地铁出行规划

一、北京地铁线路图

station存储

 

    /**
     * 站点名字.
     */
    private String name;
    /**
     * 所属线路.
     *
     */
    private String line;
    /**
     * 相邻连接站点.
     */
    private List<Station> linkStations = new ArrayList<>();

读取subway.txt并且输出routine

ublic class subway {
    public static void main(String[] args) throws IOException {

       switch (args[0]){
           case "-map":
               //-map subway.txt
               if(args.length==2){
                   DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[1];
                   //根据路径,读取地铁信息,并打印。
                   DistanceBuilder.readSubway();
                   System.out.println("成功读取subway.txt文件");
               }else{
                   System.out.println("验证参数格式!");
               }
               break;

           case "-a":
               //-a 1号线 -map subway.txt -o station.txt
               if(args.length==6){
                   DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[3];
                   DistanceBuilder.WRITE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[5];
                   DistanceBuilder.readSubway();
                   DistanceBuilder.writeLineData(args[1]);
                   System.out.println("已将结果写入station.txt文件");
               }else{

                   System.out.println("验证参数格式!");
               }
               break;
           case "-b":
               //-b 洪湖里 复兴路 -map subway.txt -o routine.txt

               if(args.length==7){
                   DistanceBuilder.FILE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[4];
                   DistanceBuilder.WRITE_PATH = System.getProperty("user.dir") + File.separator + "\\" + args[6];
                   DistanceBuilder.readSubway();
                   Result result = DijkstraUtil.calculate(new Station(args[1]), new Station(args[2]));
                   DistanceBuilder.writePassStationLine(result);
                   System.out.println("已将结果写入routine. txt文件");
               }else{
                   System.out.println("验证参数格式!");
               }
               break;
       }
    }
}

用迪杰特斯拉算法计算

public class DijkstraUtil {
    /**
     * 结果集.
     *resultMap
     */
    private static HashMap<Station, Result> resultMap = new HashMap<>();
    /**
     * 分析过的站点集合.
     *
     */
    private static List<Station> analysisList = new ArrayList<>();

    /**
     * 迪杰斯特拉算法应用在地铁的实现.
     *
     * @param star the star
     * @param end  the end
     * @return the result
     * @since hui_project 1.0.0
     */
    public static Result calculate(Station star, Station end) {
        //将开始站点加入到分析过的站点集合。
        if (!analysisList.contains(star)) {
            analysisList.add(star);
        }
        //如果开始站点等于终止站点,则设置result,设置距离和station。
        if (star.equals(end)) {
            Result result = new Result();
            
            result.setDistance(0.0D);
            result.setEnd(star);
            result.setStar(star);
            return resultMap.put(star, result);
        }
        //第一次调用calculate,且起始点和终止点不同,则resultMap为空。
        if (resultMap.isEmpty()) {
            //第一次调用获取起始点的相邻站点(在所有地铁线中,这里涉及转线交叉的周围站点)
            List<Station> linkStations = getLinkStations(star);
            //把相邻站点集合中的所有站点,加入resultMap中。 因为相邻,则可以直接获取Distance。
            for (Station station : linkStations) {

                Result result = new Result();
                result.setStar(star);
                result.setEnd(station);
                String key = star.getName() + ":" + station.getName();
                Double distance = DistanceBuilder.getDistance(key);
                result.setDistance(distance);
                result.getPassStations().add(station);
                resultMap.put(station, result);
            }
        }
        Station parent = getNextStation();
        //如果resultMap所有点keySet被分析完了,则返回的parent为null。
        if (parent == null) {
            Result result = new Result();
            result.setDistance(0.0D);
            result.setStar(star);
            result.setEnd(end);
            //put方法的返回值就是value值。
            return resultMap.put(end, result);
        }
        //如果得到的最佳邻点与目标点相同,则直接返回最佳邻点对应的result对象。
        if (parent.equals(end)) {
            return resultMap.get(parent);
        }


        //在路径经过点中加入parent后,更新resultMap集合,要么起始点经过parent达到parent相邻点是最优的,要么起始点到parent相邻点不可达,而通过parent可达。
        //获取parent对象(最佳点)的相邻点。
        //分析一个parent最佳点后,把它的相邻点都会加入到resultMap中,在下一次调用getNextStation获取resultMap中未被标记且距离(起始点到该station的距离)最短。
        List<Station> childLinkStations = getLinkStations(parent);
        //D:B C E
        for (Station child : childLinkStations) {
            if (analysisList.contains(child)) {
                continue;
            }
            String key = parent.getName() + ":" + child.getName();
            Double distance;

            distance = DistanceBuilder.getDistance(key);

            DistanceBuilder.getDistance(key);
            if (parent.getName().equals(child.getName())) {
                distance = 0.0D;
            }

            Double parentDistance = resultMap.get(parent).getDistance();
            distance = doubleAdd(distance, parentDistance);

            List<Station> parentPassStations = resultMap.get(parent).getPassStations();
            Result childResult = resultMap.get(child);
            if (childResult != null) {
                //既可以A->B,也可以通过最佳点D,从A->D->B
                if (childResult.getDistance() > distance) {
                    //如果通过最佳点比直接到距离小,则更新resultMap中的对应result对象。
                    childResult.setDistance(distance);
                    childResult.getPassStations().clear();
                    //路径更新为A->最佳点->child点。
                    childResult.getPassStations().addAll(parentPassStations);
                    childResult.getPassStations().add(child);
                }
            } else {
                //如果在resultMap中没有最佳点的相邻点,则往resultMap中添加通过最佳点(初始为起始点的最佳邻点)到达该点。
                childResult = new Result();
                childResult.setDistance(distance);
                childResult.setStar(star);
                childResult.setEnd(child);
                childResult.getPassStations().addAll(parentPassStations);
                childResult.getPassStations().add(child);
            }
            resultMap.put(child, childResult);
        }
        //初始时,即第一次调用该方法时,在分析点中加入起始点的最佳相邻点,后面嵌套调用时,就为获取某点的最佳邻点,在用最佳邻点更新resultMap后,往analysisList中加入最佳邻点。
        analysisList.add(parent);
        //加入最佳邻点后,更新resultMap,再次调用calculate
        return calculate(star, end);
        //或:
        // calculate(star, end); 继续往下走,选择最佳点,然后更新resultMap。
        // return resultMap.get(end);
    }


    /**
     * 获取所有相邻节点.
     *
     * @param station the station
     * @return the link stations
     * @since hui_project 1.0.0
     */
    //传入起始点station对象。
    public static List<Station> getLinkStations(Station station) {
        List<Station> linkedStaions = new ArrayList<Station>();

       for (List<Station> line : DistanceBuilder.lineSet) {
            for (int i = 0; i < line.size(); i++) {
                //遍历每条地铁线,若地铁线中存在该站点,则判断,如果该站点位于地铁线的起始站,则相邻站为地铁线的第二个站点(i+1),
                //如果该站点位于地铁线的最后一个站,则相邻站为地铁线的倒数第二个站点(i-1),
                //如果该站点位于地铁线的其余位置,则相邻站点为该站点前后位置(i-1/i+1)
                if (station.equals(line.get(i))) {
                    if (i == 0) {
                        linkedStaions.add(line.get(i + 1));
                    } else if (i == (line.size() - 1)) {
                        linkedStaions.add(line.get(i - 1));
                    } else {
                        linkedStaions.add(line.get(i + 1));
                        linkedStaions.add(line.get(i - 1));
                    }
                }
            }
        }
        return linkedStaions;
    }

    /**
     * 通过计算最小权值 计算下一个需要分析的点
     * 将resultMap中的station集合循环遍历,获取“未被标记的点(未在analysisList中)”中,对应result对象中距离最小的终点station对象。
     * @return the next station
     * @since hui_project 1.0.0
     */
    private static Station getNextStation() {
        Double min = Double.MAX_VALUE;
        Station rets = null;
        //获取resultMap中的station集合。
        Set<Station> stations = resultMap.keySet();
        for (Station station : stations) {
            //如果该点被标记为“已被分析”(已被分析表示起始点到该点的最短路径已求出)
            if (analysisList.contains(station)) {
                continue;
            }
            //循环分析resultMap中未被标记的点,求出最短路径的result对象。
            Result result = resultMap.get(station);
            if (result.getDistance() < min) {
                min = result.getDistance();
                //得到终点的station对象
                rets = result.getEnd();
            }
        }
        return rets;
    }

读取距离信息

    public static HashMap<String,HashMap<String,Double>> distanceMap = new HashMap<String,HashMap<String,Double>>();
    public static LinkedHashSet<List<Station>> lineSet = new LinkedHashSet<>();//所有线集合
    public static HashMap<String,List<Station>> lineData;
    private DistanceBuilder() {
    }

    static {
        createlineData();
    }
    public static void createlineData(){
        lineData = new HashMap<>();
        for (List<Station> stations : lineSet) {
            lineData.put(stations.get(1).getLine(),stations);
        }
    }
    public static String getLineNameByStation(Station station){
        createlineData();
        String startname = station.getName();
        for (Map.Entry<String,List<Station>> entry : lineData.entrySet()) {
            List<Station> stations =  entry.getValue();
            for (Station sta : stations){
                if(sta.getName().equals(startname)){
                    return entry.getKey();
                }
            }
        }
        return "";
    }

测试样例:java subway -b 万寿路 七里庄 -map subway.txt -o routine.txt

 

 

github:https://github.com/wuyuhanoch/wu

 

posted @ 2019-10-15 11:37  31701051吴雨翰  阅读(192)  评论(0编辑  收藏  举报