• 北京地铁规划项目总结


    一、项目介绍

      实现一个帮助进行地铁出行路线规划的命令行程序。

      github链接:https://github.com/blakeyoungc/subway

      主要需求:1、地铁线路图信息的导入

             2、查询指定地铁线经过的站点 

           3、计算从出发到目的站点之间的最短(经过的站点数最少)路线,并输出经过的站点的个数和路径(包括出发与目的站点)。

    采用https://map.bjsubway.com/上的北京地铁线路图:

     二、需求实现

      

    主要模块介绍:

    序号 模块名 功能 对应java类
    1 主模块(main函数) 对输入参数的控制 Main.java
    2 文件输入输出模块 txt文件的读写 Manager.java
    3 求最短路径(dij算法) 实现两个站点的最短路线查找 Subway.java

    Main函数中区分输入不同参数时执行的操作。

    public class Main {
        public static void main(String[] args)  {
            if(args.length==2||args.length==6||args.length==7) {                        //通过case分别处理不同参数输入时的操作
             switch(args[0]) {
             case "-map":
                Manager.loadfile();
                break;
             case "-a":
                Manager.loadfile(); 
                Manager.searchstations(args[1]);
                break;
             case "-b":
                Manager.loadfile(); 
                Route results=Subway.getRoutine(args[1],args[2]);
                Manager.outputroute(results);
                break;
             }
            }
            else
                System.out.println("格式错误!");
        }
    }

    车站及线路类以及其方法的设计

    车站类:

    import java.util.*;
    
    public class Station {
        private String stationName;                                               //站点名
        private String lineName;                                                  //所在路线名
        private List<Station> linkStations = new ArrayList<>();                   //存储相邻的站点
        public Station(String stationName){
            this.stationName = stationName;
        }
    
        public Station(String stationName,String lineName){
            this.stationName = stationName;
            this.lineName = lineName;
        }
    
        public String getStationName() {
            return stationName;
        }
    
        public void setStationName(String stationName) {
            this.stationName = stationName;
        }
    
        public String getLineName() {
            return lineName;
        }
    
        public void setLineName(String lineName) {
            this.lineName = lineName;
        }
    
        public List<Station> getLinkStations() {
            return linkStations;
        }
    
        public void setLinkStations(List<Station> linkStations) {
            this.linkStations = linkStations;
        }
    }

    线路类:

    public class Route {
        private Station startstation;                                                 //起点
        private Station destination;                                                  //终点
        private List<Station>passedStations=new ArrayList<>();                        //存储最短路径经过的路线站点
        public Station getStartStation() {
            return startstation;
        }
    
        public void setStartStation(Station startstation) {
            this.startstation = startstation;
        }
    
        public Station getDestination() {
            return destination;
        }
    
        public void setDestination(Station destination) {
            this.destination = destination;
        }
    
        public List<Station> getPassedStations() {
            return passedStations;
        }
    
        public void setPassedStations(List<Station> passedStations) {
            this.passedStations = passedStations;
        }
    }

    需求1、地铁线路图信息的导入

    程序启动时需要通过读取 -map 参数来获得对应的自定义地铁文件(命名为 subway.txt),从而得到地铁线路图的信息。

    示例: java subway -map subway.txt 

    通过Hashmap存储subway.txt中的线路站点信息,其中key存线路名,value存站点类的表,存到subwaymap中以供后面使用。

    public  static HashMap<String, List<Station>> subwaymap = new HashMap<>();
        public static void loadfile() {
            File file=new File("C://subway.txt");
            try {
                InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream(file),"GBK");
                BufferedReader reader=new BufferedReader(inputStreamReader);
                String data=null;
                while((data=reader.readLine())!=null) {
                String[] linedata=data.trim().split(" ");                                              //按空格分割读取txt文件的数据
                List<Station>stations=new ArrayList<>();
                for(int i = 1;i<linedata.length;i++){     
                    Station station = new Station(linedata[i],linedata[0]);
                    stations.add(station);
                    }
                    subwaymap.put(linedata[0], stations);                                              //按序存入subwaymap
                }
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    subway.txt中的北京地铁线路信息截图

    需求2、查询指定地铁线经过的站点。

    程序启动时需要通过读取 -a 参数来获得线路名,并输出该线路的站点到文件“station.txt”。

    示例: -a 10号线 -map subway.txt -o station.txt 

    把之前subwaymap中的数据根据用户输入的线路名进行筛选,有序读取该线路经过的站点并写入“station.txt”文件。

    public static void searchstations(String routename) {
            File file=new File("C://station.txt");
            try {
                OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file),"GBK");
                BufferedWriter writer = new BufferedWriter(outputStreamWriter);
                List<Station> list = subwaymap.get(routename);    
                writer.write(routename+" ");
                    for(int i=0;i<list.size();i++){
                        writer.write(list.get(i).getStationName()+" ");
                            }
                    writer.close();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

       

    查询10号线的所有站点,运行完成后station.txt结果截图 

    需求3、查询两个站点的最短路径线路及换乘信息

    程序启动时需要通过读取 -b 参数来获得输入的起点和终点,输出两个站点之间的最短路径经过的站点。

    示例: -b 巴沟 土桥 -map subway.txt -o routine.txt 

    查询从巴沟到土桥的最短路线站点及换乘线路。

    通过Dijkstra算法求最短路径。

    步骤如下:

       1:遍历所有节点找到未访问过的节点中累积权值(其实就是从源节点到当前节点的路径值和)最小的(设为A)。

       2:遍历该节点所有可达边(连通到目标节点B),如果节点A累积权值加可达边权值小于目标节点B自身的累积权值,则对目标节点B进行更新。

       3:将节点A设定为已访问。

       4:重复(1)直到所有节点均访问完毕。

    public Route Dijkstra(Route routine) {
            Station s;
            Station S;
            HashMap<Station,Station> D = new HashMap<>();
            HashMap<Station,Station> prev = new HashMap<>(); 
            HashMap<Station,Integer> searched = new HashMap<>(); 
            HashMap<HashMap<Station,Station>,Integer> distance = new HashMap<>();                                                      
            for (String key :allStation.keySet()){
                s = allStation.get(key);
                searched.put(s,new Integer(0));
                if (!routine.getStartStation().equals(s)){
                    if (routine.getStartStation().getLinkStations().contains(s)){
                        D = new HashMap<>();
                        D.put(routine.getStartStation(),s);
                        distance.put(D,new Integer(1));
                        prev.put(s,routine.getStartStation());
                    }
                    else{
                        D = new HashMap<>();                              
                        D.put(routine.getStartStation(),s);
                        distance.put(D,new Integer(Integer.MAX_VALUE));
                    }
                }
                else{
                    D = new HashMap<>();
                    D.put(routine.getStartStation(),s);
                    distance.put(D,new Integer(0));
                }
            }
            searched.put(routine.getStartStation(),1);
            while (true){
                S = FindMinDist(routine,distance,searched);    
                if (S.getStationName().equals("-1"))
                    break;
                searched.put(S,1);
                for (String key:allStation.keySet()){
                    if (S.getLinkStations().contains(allStation.get(key))&&searched.get(allStation.get(key))==0){
                        if (distance.get(getFromtoFin(routine,S))+1<distance.get(getFromtoFin(routine,allStation.get(key)))){
                            distance.put(getFromtoFin(routine,allStation.get(key)),distance.get(getFromtoFin(routine,S))+1);
                            prev.put(allStation.get(key),S);
                        }
                    }
                }
            }
            S = prev.get(routine.getDestination());
            while(!S.equals(routine.getStartStation())){
                routine.getPassedStations().add(0,S);
                S = prev.get(S);
            }
            routine.getPassedStations().add(0,routine.getStartStation());
            routine.getPassedStations().add(routine.getDestination());
            return routine;
        }

    通过算法生成最短路径后,再进行换乘线路的判断,同时将数据输出到“routine.txt”文件中。

    public static void outputroute(Route routine) {
            // TODO Auto-generated method stub
            File file=new File("C://routine.txt");
            try {
                OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file),"GBK");
                BufferedWriter writer = new BufferedWriter(outputStreamWriter);
                writer.write(routine.getPassedStations().size()-1+" ");
                String linename="0";
                 for (int i = 0; i < routine.getPassedStations().size();i++)
                    {
                        writer.write(routine.getPassedStations().get(i).getStationName()+" ");
                        if (i<routine.getPassedStations().size()-1){
                            if (!routine.getPassedStations().get(i).getLineName().equals(routine.getPassedStations().get(i+1).getLineName())){      //换乘线路的判断
                                linename = routine.getPassedStations().get(i+1).getLineName();
                                if(linename!="0")
                                writer.write("换乘"+linename+"  ");
                            }
                        }
                    }
                writer.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }

    routine.txt中的最短路线站点及换乘信息

    异常情况处理:

    起点与终点相同:-b 土桥 土桥 -map subway.txt -o routine.txt

    输出:起点与终点相同

     

    起点或终点不存在: -b 123 456 -map subway.txt -o routine.txt

    输出:起点或终点不存在

     

    查询线路不存在: -a 1000号线 -map subway.txt -o station.txt

    输出:线路不存在

     三、小结

    本次个人作业中间出现了各种错误,其实还是对java代码的熟悉度不够,实验中多次出现Exception in thread "main" java.lang.NullPointerException的错误,主要因为数组为null了,没有初始化,浪费了很多时间找错,后续还要继续学习熟悉。

  • 相关阅读:
    python学习笔记-4-列表和元组
    迭代器 生成器, 可迭代对象以及应用场景
    mysql的创创建用户阶段 开启客户端登录和授权阶段
    初识mysql数据库
    拆目录
    日志编码
    数据库mysql的安装.启动和基础配置------windows版本
    协程
    线程锁 死锁现象 递归锁 信号量 条件定时器 队列 线程池
    网络线程
  • 原文地址:https://www.cnblogs.com/31701085yc/p/11661278.html
Copyright © 2020-2023  润新知