地鐵最短路徑完整
阿新 • • 發佈:2020-11-04
專案綜述
提供一副地鐵線路圖,計算指定兩站之間最短(最少經過站數)乘車路線;輸出指定地鐵線路的所有站點。以北京地鐵為例,地鐵線路資訊儲存在data.txt中,格式如下:
地鐵線路總數
線路名
1站名
1站名
2站名
3...
線路名
2站名
1站名
2站名
3...
線路名
3站名
1站名
2站名
3...
1、需求分析
-
支援查詢指定地鐵線路的所有站點
-
支援查詢任意兩站之間最短乘車路線,包含經過站名
-
能夠輸出換乘站點、換乘站數、乘車站數
- 能夠在短時間內響應使用者,輸出資訊
2、實現語言
Java
3、實現演算法
Floyd
演算法介紹
弗洛伊德演算法定義了兩個二維矩陣:
- 矩陣D記錄頂點間的最小路徑
例如D[0][3]= 10,說明頂點0 到 3 的最短路徑為10; - 矩陣P記錄頂點間最小路徑中的中轉點
例如P[0][3]= 1 說明,0 到 3的最短路徑軌跡為:0 -> 1 -> 3。
它通過3重迴圈,k為中轉點,v為起點,w為終點,迴圈比較D[v][w] 和 D[v][k] + D[k][w] 最小值,如果D[v][k] + D[k][w] 為更小值,則把D[v][k] + D[k][w] 覆蓋儲存在D[v][w]中。
下圖能夠幫助理解概念。(參考https://blog.csdn.net/jeffleo/article/details/53349825,講解的很好,很容易理解)
4、類職責劃分
- Beanstation
private
- lineprocess-處理線路和站點資訊,建立領接領接,呼叫floyd-核心演算法,見核心程式碼部分
public lineprocess(List<G> vertices)//初始化領接矩陣函式 public void edg(G start, G stop, int weight)//新增站點之間的邊函式 public void floyd(int[][] Graph)//核心,floyd演算法 public StringBuffer output(G start, G stop,int[][] sub,List<Beanstation> lines)//查詢最短路徑並輸出函式
- readtxt-讀入文字資料
- start-UI入口
- FrmMain-UI頁面
5、核心程式碼
構造線路圖
private static final int MAX= 999; private int[][] matirx;//地鐵線路圖的鄰接矩陣 public List<G> vertex;//頂點 public int[][] getMatirx() { return matirx; } //初始化鄰接矩陣 public lineprocess(List<G> vertices) { this.vertex = vertices; int size = this.vertex.size(); this.matirx = new int[size][size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if(i==j) this.matirx[i][j]=0; else this.matirx[i][j]=MAX; } } } public void edg(G start, G stop, int a) {//站點間的邊邊 int i = vertex.indexOf(start); int j = vertex.indexOf(stop); int n = matirx.length; if (i >= 0 && i < n && j >= 0 && j < n&& this.matirx[i][j] == MAX && i != j) { this.matirx[i][j] = a; this.matirx[j][i] = a; } }
- floyd演算法-核心
private int[][] D = null;//頂點間的最小路徑值矩陣 private int[][] P = null;//對應點的最小路徑的前驅點,例如p(1,3) = 2 說明頂點1到頂點3的最小路徑要經過2 private int[][][] path = null; private int[] QAQ =null; public void floyd(int[][] Graph) { int vexnum = Graph.length;//頂點數 this.D = Graph;//初始化D矩陣 this.P = new int[vexnum][vexnum]; this.QAQ = new int[vexnum]; this.path = new int[vexnum][vexnum][]; //初始化P矩陣 for (int v = 0; v < vexnum; v++) { QAQ[v] = -1; for (int w = 0; w < vexnum; w++) P[v][w] =-1; } //這裡是弗洛伊德演算法的核心部分 //k為中間點 for (int k = 0; k < vexnum; k++) { //v為起點 for (int v = 0; v < vexnum; v++) { //w為終點 for (int w = 0; w < vexnum; w++) { if (D[v][w] > D[v][k] + D[k][w]) { D[v][w] = D[v][k] + D[k][w];//更新最小路徑 P[v][w] = k;//更新最小路徑中間頂點 } } } } //v->w的路徑 for (int v = 0; v < vexnum; v++) { int[] lenth = new int[1];//經過的點數 for (int w = 0; w < vexnum; w++) { lenth[0] = 0; //起點為v QAQ[lenth[0]++] = v; resultpath(P, v, w, QAQ, lenth);// 更新QAQ path[v][w] = new int[lenth[0]]; for (int s = 0; s < lenth[0]; s++) path[v][w][s] = QAQ[s]; } } } // 輸出v到w的路徑 private void resultpath(int[][] P, int v, int w, int[] QAQ, int[] lenth) { if (v == w) return ; if (P[v][w] == -1) QAQ[lenth[0]++] = w; else { resultpath(P, v, P[v][w], QAQ, lenth); resultpath(P, P[v][w], w, QAQ, lenth); } }
- 讀取資料
public class readtxt { public List<Beanstation> txt(String data) throws IOException{ List<Beanstation> lines=new ArrayList<Beanstation>();//存取所有線路 String fg=" ";//空格是分隔符 File file=new File(data); InputStreamReader read = new InputStreamReader(new FileInputStream(file)); BufferedReader bufferedReader = new BufferedReader(read); String Line1 = null; //讀檔案 while((Line1 = bufferedReader.readLine()) != null){ // 字串分隔 Beanstation station=new Beanstation(); String route=""; String tmp[] = Line1.split(fg); route=tmp[0]; station.setStationname(route); List<String> stations=new ArrayList<>();//站點集合 for(String s:tmp) stations.add(s); stations.remove(0); station.setStations(stations); lines.add(station);//在該線路中加站點 } return lines; } }
程式碼詳見https://github.com/31803160/subway
6、測試用例
- 初始頁面(預設顯示1號線站點)
- 檢視某路線中的所有站點
- 任意兩點線路查詢
- 同一條線
- 輸入為空
- 起點終點相同
- 輸入站點不存在
7、個人總結
瞭解了寫一個小專案的大致流程以及如何呈現在部落格上。
學習了Floyd演算法,CSDN上有很多講解的很好的部落格非常值得學習。
認清自己,適當放棄。