1. 程式人生 > >Java數據結構 最短路徑解法Dijkstra算法

Java數據結構 最短路徑解法Dijkstra算法

類型 是否 queue接口 get -s java數據結構 visit 其它 object


本文為博主原創文章,未經博主允許不得轉載!

1.1、定義概覽
Dijkstra(迪傑斯特拉)算法是典型的單源最短路徑算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。註意該算法要求圖中不存在負權邊。

問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短路徑。(單源最短路徑)

1.2、算法描述
1)算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以後每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。



2)算法步驟:
a.初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即:U={其余頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。
d.重復步驟b和c直到所有頂點都包含在S中。

技術分享

實現:

  1 public
class GraphByMatrix { 2 public static final boolean UNDIRECTED_GRAPH = false;//無向圖標誌 3 public static final boolean DIRECTED_GRAPH = true;//有向圖標誌 4 5 public static final boolean ADJACENCY_MATRIX = true;//鄰接矩陣實現 6 public static final boolean ADJACENCY_LIST = false;//
鄰接表實現 7 8 public static final int MAX_VALUE = Integer.MAX_VALUE; 9 private boolean graphType; 10 private boolean method; 11 private int vertexSize; 12 private int matrixMaxVertex; 13 14 //存儲所有頂點信息的一維數組 15 private Object[] vertexesArray; 16 //存儲圖中頂點之間關聯關系的二維數組,及邊的關系 17 private int[][] edgesMatrix; 18 19 // 記錄第i個節點是否被訪問過 20 private boolean[] visited; 21 22 /** 23 * @param graphType 圖的類型:有向圖/無向圖 24 * @param method 圖的實現方式:鄰接矩陣/鄰接表 25 */ 26 public GraphByMatrix(boolean graphType, boolean method, int size) { 27 this.graphType = graphType; 28 this.method = method; 29 this.vertexSize = 0; 30 this.matrixMaxVertex = size; 31 32 if (this.method) { 33 visited = new boolean[matrixMaxVertex]; 34 vertexesArray = new Object[matrixMaxVertex]; 35 edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex]; 36 37 //對數組進行初始化,頂點間沒有邊關聯的值為Integer類型的最大值 38 for (int row = 0; row < edgesMatrix.length; row++) { 39 for (int column = 0; column < edgesMatrix.length; column++) { 40 edgesMatrix[row][column] = MAX_VALUE; 41 } 42 } 43 44 } 45 } 46 47 /********************最短路徑****************************/ 48 //計算一個頂點到其它一個頂點的最短距離 49 public void Dijkstra(Object obj) throws Exception { 50 Dijkstra(getVertexIndex(obj)); 51 } 52 public void Dijkstra(int v0) { 53 int[] dist = new int[matrixMaxVertex]; 54 int[] prev = new int[matrixMaxVertex]; 55 56 //初始化visited、dist和path 57 for (int i = 0; i < vertexSize; i++) { 58 //一開始假定取直達路徑最短 59 dist[i] = edgesMatrix[v0][i]; 60 visited[i] = false; 61 62 //直達情況下的最後經由點就是出發點 63 if (i != v0 && dist[i] < MAX_VALUE) 64 prev[i] = v0; 65 else 66 prev[i] = -1; //無直達路徑 67 } 68 69 //初始時源點v0∈visited集,表示v0 到v0的最短路徑已經找到 70 visited[v0] = true; 71 72 // 下來假設經由一個點中轉到達其余各點,會近些,驗證之 73 // 再假設經由兩個點中轉,會更近些,驗證之,..... 74 // 直到窮舉完所有可能的中轉點 75 int minDist; 76 int v = 0; 77 for (int i = 1; i < vertexSize; i++) { 78 //挑一個距離最近經由點,下標裝入 v 79 minDist = MAX_VALUE; 80 81 for (int j = 0; j < vertexSize; j++) { 82 if ((!visited[j]) && dist[j] < minDist) { 83 v = j; // 經由頂點j中轉則距離更短 84 minDist = dist[j]; 85 } 86 } 87 visited[v] = true; 88 89 /*頂點v並入S,由v0到達v頂點的最短路徑為min. 90 假定由v0到v,再由v直達其余各點,更新當前最後一個經由點及距離*/ 91 for (int j = 0; j < vertexSize; j++) { 92 if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) { 93 94 if (minDist + edgesMatrix[v][j] <= dist[j]) { 95 //如果多經由一個v點到達j點的 最短路徑反而要短,就更新 96 dist[j] = minDist + edgesMatrix[v][j]; 97 98 prev[j] = v; //經由點的序號 99 } 100 101 } 102 } 103 104 } 105 106 for (int i = 1; i < matrixMaxVertex; i++) { 107 System.out.println("**" + vertexesArray[v0] + "-->" +vertexesArray[i] + " 的最短路徑是:" + dist[i]); 108 } 109 } 110 111 //獲取頂點值在數組裏對應的索引 112 private int getVertexIndex(Object obj) throws Exception { 113 int index = -1; 114 for (int i = 0; i < vertexSize; i++) { 115 if (vertexesArray[i].equals(obj)) { 116 index = i; 117 break; 118 } 119 } 120 if (index == -1) { 121 throw new Exception("沒有這個值!"); 122 } 123 124 return index; 125 } 126 127 /** 128 * 單源最短路徑算法,用於計算一個節點到其他!!所有節點!!的最短路徑 129 */ 130 public void Dijkstra2(int v0) { 131 // LinkedList實現了Queue接口 FIFO 132 Queue<Integer> queue = new LinkedList<Integer>(); 133 for (int i = 0; i < vertexSize; i++) { 134 visited[i] = false; 135 } 136 137 //這個循環是為了確保每個頂點都被遍歷到 138 for (int i = 0; i < vertexSize; i++) { 139 if (!visited[i]) { 140 queue.add(i); 141 visited[i] = true; 142 143 while (!queue.isEmpty()) { 144 int row = queue.remove(); 145 System.out.print(vertexesArray[row] + "-->"); 146 147 for (int k = getMin(row); k >= 0; k = getMin(row)) { 148 if (!visited[k]) { 149 queue.add(k); 150 visited[k] = true; 151 } 152 } 153 154 } 155 } 156 } 157 } 158 159 private int getMin( int row) { 160 int minDist = MAX_VALUE; 161 int index = 0; 162 for (int j = 0; j < vertexSize; j++) { 163 if ((!visited[j]) && edgesMatrix[row][j] < minDist) { 164 minDist = edgesMatrix[row][j]; 165 index = j; 166 } 167 } 168 if (index == 0) { 169 return -1; 170 } 171 return index; 172 } 173 174 public boolean addVertex(Object val) { 175 assert (val != null); 176 vertexesArray[vertexSize] = val; 177 vertexSize++; 178 return true; 179 } 180 181 public boolean addEdge(int vnum1, int vnum2, int weight) { 182 assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2 && weight >= 0); 183 184 //有向圖 185 if (graphType) { 186 edgesMatrix[vnum1][vnum2] = weight; 187 188 } else { 189 edgesMatrix[vnum1][vnum2] = weight; 190 edgesMatrix[vnum2][vnum1] = weight; 191 } 192 193 return true; 194 } 195 196 }

測試

 1 @Test  
 2 public void testWeight() throws Exception {  
 3     GraphByMatrix graph = new GraphByMatrix(Graph.UNDIRECTED_GRAPH, Graph.ADJACENCY_MATRIX, 6);  
 4   
 5     graph.addVertex("1");  
 6     graph.addVertex("2");  
 7     graph.addVertex("3");  
 8     graph.addVertex("4");  
 9     graph.addVertex("5");  
10     graph.addVertex("6");  
11   
12     graph.addEdge(0, 1,7);  
13     graph.addEdge(0, 2,9);  
14     graph.addEdge(0, 5,14);  
15   
16     graph.addEdge(1, 3,15);  
17     graph.addEdge(1, 2,10);  
18   
19     graph.addEdge(2, 3,11);  
20     graph.addEdge(2, 5,2);  
21   
22     graph.addEdge(3, 4,6);  
23     graph.addEdge(4, 5,9);  
24   
25     graph.Dijkstra(0);  
26     System.out.println();  
27     graph.Dijkstra("1");  
28     System.out.println();  
29     graph.Dijkstra2(0);  
30     System.out.println();  
31 }  

Java數據結構 最短路徑解法Dijkstra算法