个人项目——地铁线路规划

个人项目-地铁线路规划系统

GitHub项目地址:https://github.com/ye1014239226/Subway1.git

问题描述

1.输入地铁线路的名字,显示该线路上的站点信息

2.输入起末站的站点名字,输出最优的换乘路线(经过站点数量最少)

解决思路

1.收集北京地铁的线路信息,存入txt文件中,并导入到设计的数据存储方式中去

2.读入数据并且构建地铁线路图的数据结构

3.使用迪杰斯特拉算法求最短的换乘路径

4.测试

解决过程

1.数据存储

txt的存储形式如下

线路名

站点名:站点名      距离

...

站点名:站点名      距离

*线路名-站点名,....,站点

001
苹果园:古城    1
古城:八角游乐园    1
八角游乐园:八宝山    1
八宝山:玉泉路    1
玉泉路:五棵松    1
五棵松:万寿路    1...四惠:四惠东 1

*001-苹果园,古城,八角游乐园,八宝山,玉泉路,.....,四惠东

2.代码解析

Station类

存储站点信息:站点名成,所在路线,邻接站点,以地铁站名称进行唯一区分

public class Station {
    private String name;//站点名称
    private String line;//站点所属线路
    private List<Station> linkStations = new ArrayList<>();//邻接站点
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLine() {
        return line;
    }
    public void setLine(String line) {
        this.line = line;
    }
    public List<Station> getLinkStations() {
        return linkStations;
    }
    public void setLinkStations(List<Station> linkStations) {
        this.linkStations = linkStations;
    }
    public Station(String name,String line) {
        this.name=name;
        this.line=line;

    }
    public Station(String name) {
        this.name=name;
    }
    public Station() {
    }
    public int hashCode() {
        return this.getName().hashCode();
    }
    public String toString() {
        return "Station{" + "name=‘" + name +‘\‘‘ +",line=‘" + line + ‘\‘‘ + ", linkStations=" + linkStations + ‘}‘;
    }
    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;
        }
    }
}

Result类

存储运行结果

public class Result {
    private Station starStation;//输入起始站点
    private Station endStation;//输入终点站点
    private double distance=0;
    private List<Station> passStation = new ArrayList<>();//经过的站点
    public Station getStarStation() {
        return starStation;
    }
    public void setStarStation(Station starStation) {
        this.starStation = starStation;
    }
    public Station getEndStation() {
        return endStation;
    }
    public void setEndStation(Station endStation) {
        this.endStation = endStation;
    }
    public double getDistance() {
        return distance;
    }
    public void setDistance(double distance) {
        this.distance = distance;
    }
    public List<Station> getPassStation() {
        return passStation;
    }
    public void setPassStation(List<Station> passStation) {
        this.passStation = passStation;
    }
    public Result(Station starStation,Station endStation,double distance) {
        this.starStation=starStation;
        this.endStation=endStation;
        this.distance=distance;
    }
    public Result() {

    }
    public String toString() {
        return "Result{"+"starStation="+starStation+", endStation="+endStation+",distance" + distance +", passStation=" + passStation+‘}‘;
    }
}

Builder类

初始化数据(邻接点之间的距离),从txt读取初始化数据

public class Builder {
    public  static String FILE_PATH;
    public  static String WRITE_PATH;
    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 Builder() {
    }

    static {
        Create();
    }
    public static void Create(){
        lineData = new HashMap<>();
        for (List<Station> stations : lineSet) {
            lineData.put(stations.get(1).getLine(),stations);
        }
    }
    public static String getLineNameByStation(Station station){
        Create();
        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 "";
    }
    public static Double getDistance(String key) {//获取两个站之间的距离
        return distanceMap.entrySet().stream().filter(x->x.getValue().keySet().contains(key)).findFirst().get().getValue().get(key);
    }
    public static String getLineName(String key) {//获取地铁线路名字
        return distanceMap.keySet().stream().filter(x -> distanceMap.get(x).containsKey(key)).findFirst().orElse("");
    }
    public static boolean isContains(String key){
        return distanceMap.entrySet().stream().anyMatch(x->x.getValue().keySet().contains(key));
    }
    public static ArrayList<Station> getLine(String lineStr,String lineName){
        ArrayList<Station> line =  new ArrayList<Station>();
        String[] lineArr = lineStr.split(",");
        for (String s : lineArr) {
            line.add(new Station(s,lineName));
        }
        return line;
    }

    public static void getLineDate(String lineName) {//输出一条线路上所有的站点
        Create();
        lineName=lineName.substring(0,3);
         List<Station> lineInfo = lineData.get(lineName);
         String lineStr = lineInfo.stream().map(x->x.getName()).collect(Collectors.joining(",","[","]"));
         System.out.print(lineStr);
    }
    public static void getPassStation(Result result){//输出最优线路需要经过的站点以及换成线路信息
        Station starStation = result.getStarStation();
        String starLine = getLineNameByStation(starStation);
        String converLine = starLine;
        System.out.println("起始地铁线:"+starLine);
        for (Station station : result.getPassStation()) {
            if(!converLine.equals(station.getLine())){
                System.out.print("(换乘地铁线:"+station.getLine()+")");
                converLine = station.getLine();
                converLine = station.getLine();
            }
            System.out.print(station.getName() + "->");
        }
    }
    public static void readSubway() {
        File file = new File(FILE_PATH);
        BufferedReader reader = null;

        try {
            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file),"UTF-8");

            reader = new BufferedReader(inputStreamReader);
            String line = null;
            String lineName = "001";
            distanceMap.put("001",new HashMap<>());
            while ((line = reader.readLine()) != null) {//如果之前的文件为空,则不执行输出
                if(line.trim().length()==1||line.trim().length()==3||line.trim().length()==2){
                    if(line.trim().length()==3||line.trim().length()==2){
                        continue;
                    }
                    lineName = line;
                    if(!distanceMap.keySet().contains(line)){
                        distanceMap.put(line.trim(),new HashMap<>());
                    }
                }else{
                    if(line.trim().startsWith("*")){//当line以*开始时
                        String[] lineInfo = line.substring(1).split("-");//从第2个字符开始,以“-”划分成两个数组
                        lineSet.add(getLine(lineInfo[1].trim(),lineInfo[0].trim()));
                    }else{//根据空格,“:”拆分字符串,存入distanceMap中
                        String texts[] = line.split("\t");
                        String key = texts[0].trim();
                        Double value = Double.valueOf(texts[1]);
                        distanceMap.get(lineName).put(key,value);
                        String other = key.split(":")[1].trim()+":"+key.split(":")[0].trim();
                        distanceMap.get(lineName).put(other,value);
                    }
                }
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

Dijkstra类

最短路径查找

寻找分析点的所有相邻点并且记录权值,选取最短距离的邻点,循环遍历,直到没有点可以遍历

public class Dijkstra {
     private static HashMap<Station, Result> resultMap = new HashMap<>();
        private static List<Station> analysisList = new ArrayList<>();//存放已经分析过的站点(已被分析表示起始点到该点的最短路径已求出)
        public static Result calculate(Station star, Station end) {
            if (!analysisList.contains(star)) {
                analysisList.add(star);
            }//将star站点放到以及分析的站点中去
            if (star.equals(end)) {
                Result result = new Result();
                result.setDistance(0.0D);
                result.setEndStation(star);
                result.setStarStation(star);
                return resultMap.put(star, result);
            }//当star站点等于end站点,则设置result的距离为0,end站点为star站点。
            if (resultMap.isEmpty()) {  //当第一次调用calculate,并且起始点和终止点不同,那么resultMap为空。
                List<Station> linkStations = getLinkStations(star); //把相邻站点集合中的所有站点,加入resultMap中。
                for (Station station : linkStations) {
                    Result result = new Result();
                    result.setStarStation(star);
                    result.setEndStation(station);
                    String key = star.getName() + ":" + station.getName();
                    Double distance = Builder.getDistance(key);
                    result.setDistance(distance);
                    result.getPassStation().add(station);
                    resultMap.put(station, result);
                }
            }
            Station parent = getNextStation();
            if (parent == null) {//如果resultMap所有点keySet被分析完了,则返回的parent为null。
                Result result = new Result();
                result.setDistance(0.0D);
                result.setStarStation(star);
                result.setEndStation(end);
                //put方法的返回值就是value值。
                return resultMap.put(end, result);
            }
            //如果得到的最佳邻点与目标点相同,则直接返回最佳邻点对应的result对象。
            if (parent.equals(end)) {
                return resultMap.get(parent);
            }//分析一个parent最佳点后,把它的相邻点都会加入到resultMap中,在下一次调用getNextStation获取resultMap中未被标记且距离(起始点到该station的距离)最短。
            List<Station> childLinkStations = getLinkStations(parent);
            for (Station child : childLinkStations) {
                if (analysisList.contains(child)) {
                    continue;
                }
                String key = parent.getName() + ":" + child.getName();
                Double distance;
                distance = Builder.getDistance(key);
                Builder.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).getPassStation();
                Result childResult = resultMap.get(child);
                if (childResult != null) {
                    if (childResult.getDistance() > distance) { //如果通过最佳点比直接到距离小,则更新resultMap中的对应result对象。
                        childResult.setDistance(distance);
                        childResult.getPassStation().clear();
                        childResult.getPassStation().addAll(parentPassStations);
                        childResult.getPassStation().add(child);//路径更新为A->最佳点->child点。
                    }
                } else {
                    //如果在resultMap中没有最佳点的相邻点,则往resultMap中添加通过最佳点(初始为起始点的最佳邻点)到达该点。
                    childResult = new Result();
                    childResult.setDistance(distance);
                    childResult.setStarStation(star);
                    childResult.setEndStation(child);
                    childResult.getPassStation().addAll(parentPassStations);
                    childResult.getPassStation().add(child);
                }
                resultMap.put(child, childResult);
            }
            analysisList.add(parent);
             calculate(star, end);
             return resultMap.get(end);//循环遍历得到最好的结果
        }
        public static void reMake() {//清空分析点的集合以及结果Map
            analysisList.clear();;
            resultMap.clear();;
        }
        public static List<Station> getLinkStations(Station station) {//找出所有的邻接点
            List<Station> linkedStaions = new ArrayList<Station>();

           for (List<Station> line : Builder.lineSet) {//遍历每条地铁线
                for (int i = 0; i < line.size(); i++) {
                    if (station.equals(line.get(i))) {
                        if (i == 0) {   //如果该站点位于地铁线的起始站,则相邻站为地铁线的第二个站点(i+1),
                            linkedStaions.add(line.get(i + 1));
                        } else if (i == (line.size() - 1)) {//如果该站点位于地铁线的最后一个站,则相邻站为地铁线的倒数第二个站点(i-1),
                            linkedStaions.add(line.get(i - 1));
                        } else {  //如果该站点位于地铁线的其余位置,则相邻站点为该站点前后位置(i-1/i+1)
                            linkedStaions.add(line.get(i + 1));
                            linkedStaions.add(line.get(i - 1));
                        }
                    }
                }
            }
            return linkedStaions;
        }
        private static Station getNextStation() {//计算最小的权重值,计算下一个需要分析的点
            Double min = Double.MAX_VALUE;
            Station rets = null;
            Set<Station> stations = resultMap.keySet();//获取resultMap中的station集合
            for (Station station : stations) {
                if (analysisList.contains(station)) {//如果该点被标记为“已被分析”,则跳过分析
                    continue;
                }
                //循环比较resultMap中未被标记的点,求出最短路径的result对象。
                Result result = resultMap.get(station);
                if (result.getDistance() < min) {
                    min = result.getDistance();
                    rets = result.getEndStation();
                }
            }
            return rets;//返回下一个站点
        }
        private static double doubleAdd(double v1, double v2) {
            BigDecimal b1 = new BigDecimal(Double.toString(v1));
            BigDecimal b2 = new BigDecimal(Double.toString(v2));
            return b1.add(b2).doubleValue();
        }
}

test类

首先根据路径获得subway.txt,调用read()函数中的readSubway()函数读取,并存入

根据输入格式不同,选择不同的输出方式

public class test {
     public static void main(String[] args) {
            read();
            System.out.println("线路:001,002,004,005,006,007,008,009,010,013,14东,14西,015,八通线,昌平线,亦庄线,房山线,机场线");
          while(true) {//循环输入
            write();
            Dijkstra.reMake();
            }
        }
        public static void read(){
            Builder.FILE_PATH=System.getProperty("user.dir") + File.separator + "\\" +"subway2.txt";//获取当前项目路径
            Builder.readSubway();
        }
        public static void write() {
            Scanner input=new Scanner(System.in);
            System.out.print("输入指令:(查询地铁线路信息:-a 001号线),(查询起末站线路:-b 苹果园 玉泉路):");
             String s=input.nextLine();
             String[] split =s.split("\\s+");
             switch(split[0]) {
             case "-map":
                 if(split.length==1){
                       Builder.readSubway();
                       System.out.println("成功读取subway.txt文件");
                   }else{
                       System.out.println("重新输入");
                   }
                   break;
             case "-a":
                  if(split.length==2){
                       Builder.readSubway();
                       Builder.getLineDate(split[1]);
                   }else{

                       System.out.println("重新输入");
                   }
                   break;
               case "-b":
                   if(split.length==3){
                       if(split[1].equals(split[2])) {//起末站相同,github中未修改
                           System.out.print("起末站相同,请重新输入");
                       }
                       else {
                       Builder.readSubway();
                       Result result = Dijkstra.calculate(new Station(split[1]), new Station(split[2]));
                       Builder.getPassStation(result);
                       }
                   }else{
                       System.out.println("重新输入");
                   }
                   break;
             }
                System.out.println();
        }
}

测试


1.输入地铁线路的名字,显示改线路上的站点信息

2.输入起末站,显示最优路径(经过站点数最少)

1)在一条地铁线上

2)在不同的地铁线上

3)起末站相同

4)末站不存在

问题与个人小结

本次作业,借鉴了网上的代码并做出了修改,实现了多次输入输出,但算法依旧存在问题,当输入的起站不存在时,算法会出错。

通过本次作业,初步了解并且会使用github,在一定程度上重新了解了java项目的基本流程

原文地址:https://www.cnblogs.com/zucc31701087/p/11663997.html

时间: 2024-11-08 07:30:53

个人项目——地铁线路规划的相关文章

北京地铁线路规划

北京地铁线路规划 任务 个人项目的主要任务就是通过地铁出行的人能够通过该软件很快找到最快到达目的地的出行线路规划. 项目需求 用户根据-map参数来获得所有北京地铁线路信息 java subway -map subway.txt 那么这里的重点就在于如何存储这个subway.txt文件了,首先我们还是看一张北京地铁1号线的图 ![](https://img2018.cnblogs.com/blog/1806411/201909/1806411-20190922113916097-18761194

个人项目——北京地铁线路规划

一.前言 现实和理想的差距总是那么大,在过程中碰到的坑比预期的还多(说那么多,其实就是自己菜),过程中复习了淡忘已久的许多算法和数据结构,一边深刻的体会着自己是多菜,一边也体会到了自身一点点微小的进步,大概. 二.项目简介 实现北京地铁查询功能 附上一张北京地铁的图: 三.项目地址 https://github.com/fireworks-EX/MetroLinePlanning 四.需求分析 1.确定储存及读取地铁线路数据文件的格式 2.支持用户输入的地铁线路的查询 3.提供用户指定两站点间的

个人项目--北京地铁线路规划(已完成)

一.任务: 实现一个帮助进行北京地铁出行路线规划的命令行程序. 二.需求分析及实现 需求1 在程序启动时,自动获取到地图信息 需要实现一个支持自动加载subway.txt 文件的程序 需求2 查询指定地铁线经过的站点 在应用程序上,需要支持一个新的命令行参数  -a ,指定用户希望查询的地铁线路. 在给定地铁线路时,程序需要从线路的起始站点开始,依次输出该地铁线经过的所有站点,直到终点站.输出的文件使用-o参数来指定. 一个调用应用程序的示例如下: java subway -a 1号线 -map

个人项目——地铁线路的最短路径

地铁路线规划的初步分析 支持环境 windows7, 10, macOS, linux 需求分析 1.读取一定格式下的地铁信息文件 2.提供详细的地铁信息的查询 3.提供最短路的计算与推荐功能:路线最短,时间最短,换地铁数最少... 4.UI展示 设计实现 1.基本线路设计表(概念设计如下): 开始时只保存同一站点下相邻的站点 最后生成站点间两两的最优路线 初始信息表: 出发站点 目的站点 经过地铁 肿瘤医院 天津宾馆 5号线.6号线 大王庄 十一经路 9号线 大学城 王顶堤 3号线 大毕庄 南

地铁线路规划

一.预期计划 1.选择合适的文件储存地铁路线的信息. 2.设计关于地铁信息的IO程序. 3.用户可以查询地铁信息. 4.可以推荐输入站点之间的最短路径. 5.代码复审已经性能测试. 二.需求分析 1.将地铁的具体信息储存在文件中,包括站点名称.线路名称等,要确定文件的格式,保证文件能够方便读取. 2.用户输入指定线路或者起始站和终点站,系统要给出相应的推荐线路,列出途径的站点. 3.提供查询功能,输入线路名称后系统输出这条线路上的全部站点. 三.设计思路 1.最关键的算法是查找最短路径,即在图中

个人项目——地铁线路

个人git 一.项目需求 1.该程序能够准确地读出.txt文件中的数据,文件格式简洁易懂.可灵活扩展 2.在某号线路上,能够查询各个站点的信息,输出该号线路上所有站点信息 3.在出发站与目的站之间输出一个最短路径 二.文件存储 三.文件位置 一共三个package:control.main.model control包里有Dijkstra.java,distance.java Dijkstra.java(此代码为最短路径算法,这是最核心最难的地方,dijkstra算法能很好地解决最短路径问题,这

天津地铁出行线路规划项目需求分析与设计思路分析

天津地铁出行线路规划项目需求分析与设计思路分析 项目概要 以下是天津地铁线路总图,本项目的受众可以通过本软件,获得天津市地铁出行最便捷,最快速的线路推荐. 需求分析 实现一个帮助进行地铁出行路线规划的命令行程序. 支持地铁线路的更改,站点更改.取消与添加,以及线路的局部封闭. 支持查询线路的所有站点. 支持查询到某终止站点的途径最少站点的路线. 数据存储结构分析 由于单一的线路表与站点表是无法表示如此复杂的地铁线路情况的. 有多个前驱的站点如:,以及有多个后继的站点如:,这种情况无法只通过这两个

天津地铁线路最短路径计算项目规划

天津地铁线路路径查询项目规划 一.项目介绍 实现一个帮助进行地铁出行路线规划的命令行程序. 二.项目完成预估表 PSP 2.1 Personal Software Process Stages Time Time Planning 计划 · Estimate · 估计这个任务需要多少时间 1day Development 开发 · Analysis · 需求分析 (包括学习新技术) 3day · Design Spec · 生成设计文档 1day · Design Review · 设计复审 (

北京地铁出行线路规划——个人项目

项目地址 详见: 一.基本功能 获取地铁线路图. 以参数 -map 作为标志,来获得对应的自定义地铁线路图信息文件(命名为 Subway.txt).输入格式如: java Subway -map Subway.txt 获取指定地铁线路. 以参数 -a 作为标志,并输入指定地铁线路,输出的文件以参数 -o 来指定.从线路的起始站点开始,依次输出该地铁线经过的所有站点,直到终点站.输入格式如: java Subway -a 1号线 -map Subway.txt -o Station.txt 输入起