个人作业-北京地铁出行路线规划命令行程序完成总结

北京地铁出行路线规划命令行程序 完成总结

GitHub:https://github.com/shysimon/my_subway

项目具体功能、使用方法以及算法思想,见上一篇博客:https://www.cnblogs.com/shysimon/p/11559850.html

各模块功能介绍

cn.edu.zucc.shy.model.Line:地铁线路类

cn.edu.zucc.shy.model.Station:地铁站类

cn.edu.zucc.shy.model.Edge:存储地铁站相邻地铁站的编号及所属线路

cn.edu.zucc.shy.model.NowAt:存储当前状态信息,在dijkstra算法中作为优先队列存储的数据结构单元

cn.edu.zucc.shy.manager.FindWay:存储地铁地图信息,查询后直接输出到输出流(文件或控制台,参数决定)

FindWay map = new FindWay(filepath);
//输入文件路径,初始化寻路类
map.outWay(start, end, output);
//输入起始站,目的站,输出流,直接在输出流输出找到的路
map.outLineInf(linename ,output);
//输入线路名称,输出流,直接在输出流输出该线路

cn.edu.zucc.shy.manager.TxtLineReader:读取一行文件作为一条地铁线

ArrayList<Line> lines = TxtLineReader.read(filepath);
//输入文件路径 将地铁线路文件转换成 地铁线路表

cn.edu.zucc.shy.manager.ArgsReader:处理程序输入参数以及异常处理

Pair<Integer, ArrayList<Object>> in = ArgsReader.argsReader(args);
//输入命令行参数,返回处理之后的数据,并提供异常处理

cn.edu.zucc.shy.Main: 根据manager.ArgsReader返回的参数,使用manager.FindWay中对应的方法

subway:程序的入口,直接调用Main

寻路算法的具体实现

数据在程序运行过程中的存储

地铁线路信息文件为本程序的必备参数,读取 subway.txt 文件后调用 FindWay 的带参构造函数

使用 ArrayList<Line> lines 存储地铁线路,每条线路也是使用 ArrayList<Station>;

使用 ArrayList<Pair<String, Vector<Pair<Integer, Integer>>>> stations 存储所有站点的名字以及所有位置,使得每一个站点有且只有一个下标;

使用 Map<String, Integer> mpLine 存储地铁线路对应地铁线路在 lines 中的下标;

使用 Map<String, Integer> mpStation 存储地铁站名对应地铁站在 stations 中的下标;

        for (int i = 0; i < lines.size(); i++) {
            mpLine.put(lines.get(i).getName(), i);
            for (int j = 0; j < lines.get(i).getStations().size(); j++) {
                String stationName = lines.get(i).getStations().get(j).getName();
                if (mpStation.get(stationName) == null) {
                    Vector<Pair<Integer, Integer>> p = new Vector<>();
                    p.add(new Pair<>(i, j));
                    stations.add(new Pair<>(stationName, p));
                    mpStation.put(stationName, stations.size() - 1);
                } else {
                    stations.get(mpStation.get(stationName)).getValue().add(new Pair<>(i, j));
                }
            }
        }

使用 ArrayList<Vector<Edge>> 存储地铁线路的邻接表。

for (int i = 0; i < lines.size(); i++) {
            int u = mpStation.get(lines.get(i).getStations().get(0).getName());
            for (int j = 1; j < lines.get(i).getStations().size(); j++) {
                int v = mpStation.get(lines.get(i).getStations().get(j).getName());
                edges.get(u).add(new Edge(v, i));
                edges.get(v).add(new Edge(u, i));
                u = v;
            }
        }

输出对应地铁线路的所有站点信息

直接在 mpLine 找到对应的线路的下标,在lines中找到输出

寻找最短路的过程

先在 mpStation 中找到对应起点、终点的下标,在 stations 找到所有可能的初始状态(换成站可以选择多条线路),对于每一种初始状态,都跑一遍最短路,输出在长度最短的情况下换乘最少的情况。

输出路径以及换乘线路信息的方法是,使用优先队列优化的 dijkstra 算法中,每次进入新的节点,就将进入时的状态保存在当前站点下标位置的数组中,保存的状态包括前一个站点的下标,当前所在的线路下标。这样,在找到最短路之后,从终点反着找回去,即可得到完整最短路,以及换成线路的信息。

关键代码:

                        r = new StringBuilder();
                        int now = en, line = path[now].atLine;
                        while (now != -1) {
                            r.insert(0, " " + stations.get(now).getKey());
                            now = path[now].from;
                            if (now == -1 || path[now].atLine != line) {
                                int oldLine = line;
                                if (now != -1) {
                                    r.insert(0, " " + stations.get(now).getKey());
                                    line = path[now].atLine;
                                }
                                r.insert(0, "
<" + lines.get(oldLine).getName() + ">");
                            }
                        }
                        output.write("从 "+start+" 到 "+end+" 共经过" + (minChange + 1) + "条线路," + (minLength + 1) + "个站点" + r);

输出效果如下:

从 苹果园 到 德茂 共经过6条线路,25个站点
<1号线> 苹果园 古城 八角游乐园 八宝山 玉泉路 五棵松 万寿路 公主坟 军事博物馆
<9号线> 军事博物馆 北京西站
<7号线> 北京西站 湾子 达官营 广安门内 菜市口
<4号线> 菜市口 陶然亭 北京南站
<14号线东段> 北京南站 永定门外
<8号线南段> 永定门外 木樨园 海户屯 大红门南 和义 东高地 火箭万源 五福堂 德茂
原文地址:https://www.cnblogs.com/shysimon/p/11651779.html