1. 程式人生 > 實用技巧 >地鐵最短路徑

地鐵最短路徑

個人專案——地鐵最短路徑

專案介紹

主要功能

提供一副地鐵線路圖,計算指定兩站之間最短(最少經過站數)乘車路線;輸出指定地鐵線路的所有站點。以北京地鐵為例,地鐵線路資訊儲存在data.txt中,格式如下:

地鐵線路總數
線路名1 站名1 站名2 站名3 ...
線路名2 站名1 站名2 站名3 ...
線路名3 站名1 站名2 站名3 ......

1、問題需求

  • 程式能正確處理輸入的命令列、
  • 程式能正確輸出指定地鐵線經過的站點
  • 程式能正確輸出兩個站點間的最短路徑

2、實現語言

java

3、實現演算法

Dijkstra

4、類職責劃分

Station.java 儲存站資訊
Subway.java Main函式

MyMap.java

儲存map資訊

Line.java 儲存線路資訊

5、核心程式碼

  • 讀入txt
public static void readText(String fileName) throws IOException {
        File file = new File(fileName); 
        InputStreamReader reader = new InputStreamReader(
                new FileInputStream(file));
        BufferedReader br 
= new BufferedReader(reader); String content = null; content = br.readLine(); while (content != null) { String[] contents=content.split(","); Line line = new Line(); line.setLineName(contents[0]); Station station = null
; for (int i = 1; i < contents.length; i++) { if(!MyMap.stationMap.containsKey(contents[i])) { station = new Station(); station.setStationName(contents[i]); } station = MyMap.myMap.getStation(contents[i]); station.setLine(line); line.addStation(station); if(i!=1) { station.addPreStation(line.getStation(i-2)); line.getStation(i-2).addPostStation(station); } else { station.addPreStation(null); } if(i==contents.length-1) { station.addPostStation(null); } } content = br.readLine(); // 一次讀入一行資料 } br.close(); }
  • 輸出線路的站點資訊
public static void printStationList(String lineName, String fileName) throws IOException {
        File writename = new File(fileName); // 相對路徑
        writename.createNewFile(); // 建立新檔案
        BufferedWriter out = new BufferedWriter(new FileWriter(writename));
        Line line = MyMap.myMap.getLine(lineName);
        System.out.println(lineName+":");
        out.write(lineName+"\r\n"); // \r\n為換行
        out.flush(); // 把快取區內容壓入檔案
        for (Station station : line.getStationList()) {
            System.out.println(station.getStationName());
            out.write(station.getStationName()+"\r\n"); // \r\n為換行
            out.flush(); // 把快取區內容壓入檔案
        }
        out.close();
    }
  • 輸出最短路徑
public static void printShortestLine(String startStation, String endStation, String fileName) throws IOException {
        File writename = new File(fileName); // 相對路徑
        writename.createNewFile(); // 建立新檔案
        BufferedWriter out = new BufferedWriter(new FileWriter(writename));
        Station start = MyMap.myMap.getStation(startStation);
        Station end = MyMap.myMap.getStation(endStation);
        bfs(start,end);
        Stack<Station> stationStack = new Stack<Station>();
        Stack<Line> lineStack = new Stack<Line>();
        Station cur=end;
        while(cur!=null) {
            stationStack.push(cur);
            List<Line> line = new ArrayList<Line>();
            line.addAll(cur.getLineList());//list拷貝
            //System.out.println(cur.getStationName());
            //System.out.println(cur.getParent().getStationName());
            cur = cur.getParent();
            if(cur==null)
                break;
            line.retainAll(cur.getLineList());//取交集
            lineStack.push(line.get(0));//預設交集只有一個
        }
        Line preLine = lineStack.peek();
        Line curLine = null;
        while(!stationStack.isEmpty()) {
            Station station = stationStack.pop();
            out.write(station.getStationName()+"  "); // \r\n為換行
            out.flush(); // 把快取區內容壓入檔案
            System.out.print(station.getStationName());
            if(!lineStack.empty()) {
                curLine = lineStack.pop();
                if(curLine!=preLine) {
                    System.out.print(curLine.getLineName());
                    out.write(curLine.getLineName()); // \r\n為換行
                    out.flush(); // 把快取區內容壓入檔案
                }
                preLine = curLine;
            }
            out.write("\r\n"); // \r\n為換行
            out.flush(); // 把快取區內容壓入檔案
            System.out.print("\n");
            
        }
        out.close();
    }

  • Station類
    private String stationName;
    private List<Line> lineList;
    private List<Station> preStation;
    private List<Station> postStation;
    private Station parent;
  • Line類
    private String lineName;
    private List<Station> stationList;
  • MyMap類
    public static MyMap myMap = new MyMap();
    public static java.util.Map<String, Line> lineMap;
    public static java.util.Map<String, Station> stationMap;

  • bfs廣度優先搜尋
public static void bfs(Station start, Station end) {
        Queue<Station> queue = new LinkedList<Station>();
        queue.add(start);
        while(!queue.isEmpty()) {
            Station cur = queue.poll();
            MyMap.myMap.visited(cur);
            if(cur == end)
                break;
            List<Station> list = new ArrayList<Station>();
            list.addAll(cur.getPreStation());
            list.addAll(cur.getPostStation());
            for(Station station : list) {
                if(station!=null&&!MyMap.myMap.isVisited(station)) {
                    station.setParent(cur);
                    queue.add(station);
                }
            }
            
        }

    }

6、測試用例

  • 一條線路起始到另外一條線路終點
-b 香山 焦化廠 -map 地鐵線路資訊.txt -o shortest.txt
香山
植物園
萬安
茶棚
頤和園西門
巴溝10號線
蘇州街
海淀黃莊4號線大興線
人民大學
魏公村
國家圖書館
動物園
西直門2號線
積水潭
鼓樓大街
安定門
雍和宮
東直門
東四十條
朝陽門6號線
東大橋
呼家樓
金臺路14號線東段
大望路
九龍山7號線
大郊亭
百子灣
化工
南樓梓莊
歡樂谷景區
雙合
焦化廠
  • 輸入命令有誤
-b 香山  -map 地鐵線路資訊.txt -o shortest.txt
錯誤命令!
正確命令格式:
匯入站點資訊:java subway -map subway.txt
查詢線路資訊:java subway -a 1號線 -map subway.txt -o station.txt
查詢站點間最短路程:java subway -b 站點1 站點2 -map subway.txt -o routine.txt

7、總結

Dijkstra還是不太熟悉,使用起來有些困難