#北京地铁线路推荐项目 ##1、项目介绍 ###Github:github.com/LinXS597/BeijingSubway ##2、需求分析java
##3、主要功能模块介绍git
序号 | 模块名称 | 主要功能 | 对应Java文件 |
---|---|---|---|
1 | 主模块 | 流程控制、参数解析 | src/cn/edu/zucc/Main.java |
2 | 核心算法模块 | 实现Dijkstra算法 | src/cn/edu/zucc/core/DijkstraUtil.java |
3 | 输入输出模块 | 读出和写入txt文件数据 | src/cn/edu/zucc/data/FileManager.java |
4 | 存储模块 | 存储读入的站点与线路信息 | src/cn/edu/zucc/model/Station.java |
存储输出的推荐线路信息 | src/cn/edu/zucc/model/Routine.java |
###一、主模块:流程控制、参数解析github
支持采用参数 -map 做为标志,来获取对应的自定义地铁文件,例如:算法
java subway -map subway.txt
测试
支持采用参数 -a 来指定地铁线路,采用参数 -o 来输出到指定文件station.txt,例如:命令行
java subway -a 1号线 -map subway.txt -o station.txt
设计
支持采用参数 -b 来指定出发地与目的地,例如:code
java subway -b 天安门西 北京大学东门 -map subway.txt -o routine.txt
blog
###二、核心算法模块:实现Dijkstra算法get
利用 HashMap 存储所有的站点信息,并以站点名称为key
public static HashMap<String,Station> allStation = new HashMap<>();
执行算法前先对数据进行预处理操做,主要目的有三个:
具体代码以下
public static Routine getRoutine ( String begin,String end) { Routine routine = new Routine(); List<Station> lineStationlist = null; Station station = null; Station repeatstation = null; for(String key:FileManager.subwayLineinfo.keySet()){ //遍历各条线路信息,将station去除重后加入allStation之中 lineStationlist = FileManager.subwayLineinfo.get(key); for(int i = 0;i<lineStationlist.size();i++){ station = lineStationlist.get(i); if(allStation.keySet().contains(station.getStationName())){ //判断是否重复 repeatstation = allStation.get(station.getStationName()); if (i==0){ //完善各个Sation中相邻站点LinkStation信息 repeatstation.getLinkStations().add(lineStationlist.get(i+1)); }else if(i==lineStationlist.size()-1){ repeatstation.getLinkStations().add(lineStationlist.get(i-1)); }else{ repeatstation.getLinkStations().add(lineStationlist.get(i+1)); repeatstation.getLinkStations().add(lineStationlist.get(i-1)); } continue; } else{ if (i==0){ station.getLinkStations().add(lineStationlist.get(i+1)); }else if(i==lineStationlist.size()-1){ station.getLinkStations().add(lineStationlist.get(i-1)); }else{ station.getLinkStations().add(lineStationlist.get(i+1)); station.getLinkStations().add(lineStationlist.get(i-1)); } allStation.put(station.getStationName(),station); if(station.getStationName().equals(begin)){ //根据传入参数,肯定起点,并加入到routine之中 routine.setBeginStation(station); } if(station.getStationName().equals(end)){ //根据传入参数,肯定终点,并加入到routine之中 routine.setEndStation(station); } } } } if (routine.getBeginStation().equals(routine.getEndStation())){ //一些异常状况的处理 System.out.println("起点与终点相同,请从新输入"); return null; } else if (routine.getBeginStation() == null){ System.out.println("起点不存在"); return null; } else if (routine.getEndStation() == null){ System.out.println("终点不存在"); return null; } else{ routine = new DijkstraUtil().Dijkstra_algorithm(routine); } return routine; }
HashMap<HashMap<Station,Station>,Integer> distance = new HashMap<>();
HashMap<Station,Station> path = new HashMap<>();
具体代码以下:
public Routine Dijkstra_algorithm ( Routine routine ) { HashMap<HashMap<Station,Station>,Integer> distance = new HashMap<>(); //储存各站点之间的最短距离,以Integer为单位,表示站点数 HashMap<Station,Integer> collected = new HashMap<>(); //判断该Station是否被访问过 HashMap<Station,Station> path = new HashMap<>(); //存储某个指定站点的前一个站点 HashMap<Station,Station> disitem = new HashMap<>(); Station item; Station V; for (String key :allStation.keySet()){ //初始化distance、collected与path item = allStation.get(key); collected.put(item,new Integer(0)); if (!routine.getBeginStation().equals(item)){ if (routine.getBeginStation().getLinkStations().contains(item)){ //若与起点相邻,则将距离设置为1,并将对应的path设置为起点 disitem = new HashMap<>(); disitem.put(routine.getBeginStation(),item); distance.put(disitem,new Integer(1)); path.put(item,routine.getBeginStation()); } else{ disitem = new HashMap<>(); //若未与起点相邻,则将初值设置为10000 disitem.put(routine.getBeginStation(),item); distance.put(disitem,new Integer(10000)); } } else{ disitem = new HashMap<>(); disitem.put(routine.getBeginStation(),item); distance.put(disitem,new Integer(0)); } } collected.put(routine.getBeginStation(),1); while (true){ V = FindMinDist(routine,distance,collected); //取未被访问顶点中distance最小者 if (V.getStationName().equals("-1")) //若这样的V不存在,算法结束 break; collected.put(V,1); for (String key:allStation.keySet()){ //遍历每一个站点 if (V.getLinkStations().contains(allStation.get(key))&&collected.get(allStation.get(key))==0){ if (distance.get(getFromtoFin(routine,V))+1<distance.get(getFromtoFin(routine,allStation.get(key)))){ //若收录的顶点使distance变小,则进行更新 distance.put(getFromtoFin(routine,allStation.get(key)),distance.get(getFromtoFin(routine,V))+1); path.put(allStation.get(key),V); } } } } V = path.get(routine.getEndStation()); while(!V.equals(routine.getBeginStation())){ //将最短路径各站点数据存入routine之中 routine.getPassStations().add(0,V); V = path.get(V); } routine.getPassStations().add(0,routine.getBeginStation()); routine.getPassStations().add(routine.getEndStation()); return routine; //返回 }
###三、输入输出模块与存储模块:读出和写入txt文件数据
public static String READ_FILE; public static String WRITE_FILE;
利用HashMap存储线路数据
public static HashMap<String, List<Station>> subwayLineinfo = new HashMap<>();
存储站点信息的Station类设计
private String stationName; //站点名称 private String lineName; //线路名称 private List<Station> linkStations = new ArrayList<>(); //相邻站点
private Station beginStation; //出发站点 private Station endStation; //结束站点 private List<Station> passStations = new ArrayList<>(); //最短路径上的站点
subway.txt 文件设计以下:
1号线 站点1 站点2 ... 2号线 站点1 站点2 ... 3号线 站点1 站点2 ... ...
station.txt 文件设计以下:
1号线 站点1 站点2 站点3 ...
routine.txt 文件设计以下:
11 天安门西 西单 复兴门 --->换乘地铁--<2号线>-- 阜成门 车公庄 西直门 --->换乘地铁--<13号线>-- 大钟寺 知春路 --->换乘地铁--<10号线>-- 知春里 海淀黄庄 --->换乘地铁--<4号线大兴线>-- 中关村 北京大学东门
写入时需判断相邻的两个站点是否在同一条线路上,若是不在,则需更新线路信息并写入routine.txt中
public static String getLineNmae(Station station1,Station station2){ //判断两个站点是否在同一条线路上 String res = null; List<Station> item; for (String key : subwayLineinfo.keySet()){ item = subwayLineinfo.get(key); if (item.contains(station1)&&item.contains(station2)){ return key; //若是是,返回线路名称,不然,返回null } } return res; }
##4、测试分析
###1) 重要功能测试
读入文件,命令行参数为:-map subway.txt
查询线路,命令行参数为:-a 1号线 -map subway.txt -o station.txt
###2) 核心功能测试
查询最短线路,命令行参数为:-b 天安门西 北京大学东门 -map subway.txt -o routine.txt
###3) 异常状况处理测试:
起点与终点相同:-b 天安门西 天安门西 -map subway.txt -o routine.txt
起点或终点不存在: -b 天安门西 杭州东站 -map subway.txt -o routine.txt
查询线路不存在: -a 20号线 -map subway.txt -o station.txt
命令行参数格式错误: -f 天安门西 天安门西 -map subway.txt -o routine.txt