#北京地鐵線路推薦項目 ##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