從某頂點出發,沿圖的邊到達另外一頂點所通過的路徑中,各邊上權值之和最小的一條路徑叫作最短路徑java
圖的最短路徑有許多重要的應用。node
例如:上圖中v0-v8有9個點,能夠看作不一樣的地點,如今要規劃出v0到其它某個點地點的最短路線規劃算法
構建最短路徑中比較常見的一種算法即爲dijstra(迪傑斯特拉)算法數組
究竟什麼是迪傑斯特拉算法?它是如何尋找圖中頂點的最短路徑呢?測試
這個算法的本質,是不斷刷新起點與其餘各個頂點之間的 「距離表」。this
讓咱們來演示一下迪傑斯特拉的詳細過程:spa
第1步,建立距離表。表中的Key是頂點名稱,Value是從起點A到對應頂點的已知最短距離。可是,一開始咱們並不知道A到其餘頂點的最短距離是多少,Value默認是無限大:3d
第2步,遍歷起點A,找到起點A的鄰接頂點B和C。從A到B的距離是5,從A到C的距離是2。把這一信息刷新到距離表當中:code
第3步,從距離表中找到從A出發距離最短的點,也就是頂點C。blog
第4步,遍歷頂點C,找到頂點C的鄰接頂點D和F(A已經遍歷過,不須要考慮)。從C到D的距離是6,因此A到D的距離是2+6=8;從C到F的距離是8,因此從A到F的距離是2+8=10。把這一信息刷新到表中:
接下來重複第3步、第4步所作的操做:
第5步,也就是第3步的重複,從距離表中找到從A出發距離最短的點(C已經遍歷過,不須要考慮),也就是頂點B。
第6步,也就是第4步的重複,遍歷頂點B,找到頂點B的鄰接頂點D和E(A已經遍歷過,不須要考慮)。從B到D的距離是1,因此A到D的距離是5+1=6,小於距離表中的8;從B到E的距離是6,因此從A到E的距離是5+6=11。把這一信息刷新到表中:
(在第6步,A到D的距離從8刷新到6,能夠看出距離表所發揮的做用。距離表經過迭代刷新,用新路徑長度取代舊路徑長度,最終能夠獲得從起點到其餘頂點的最短距離)
第7步,從距離表中找到從A出發距離最短的點(B和C不用考慮),也就是頂點D。
第8步,遍歷頂點D,找到頂點D的鄰接頂點E和F。從D到E的距離是1,因此A到E的距離是6+1=7,小於距離表中的11;從D到F的距離是2,因此從A到F的距離是6+2=8,小於距離表中的10。把這一信息刷新到表中:
第9步,從距離表中找到從A出發距離最短的點,也就是頂點E。
第10步,遍歷頂點E,找到頂點E的鄰接頂點G。從E到G的距離是7,因此A到G的距離是7+7=14。把這一信息刷新到表中:
第11步,從距離表中找到從A出發距離最短的點,也就是頂點F。
第10步,遍歷頂點F,找到頂點F的鄰接頂點G。從F到G的距離是3,因此A到G的距離是8+3=11,小於距離表中的14。把這一信息刷新到表中:
就這樣,除終點之外的所有頂點都已經遍歷完畢,距離表中存儲的是從起點A到全部頂點的最短距離。顯然,從A到G的最短距離是11。(路徑:A-B-D-F-G)
/** * 建立圖 */ public void createGraph(){ int [] a1 = new int[]{0,1,5,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT}; int [] a2 = new int[]{1,0,3,7,5,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT}; int [] a3 = new int[]{5,3,0,MAX_WEIGHT,1,7,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT}; int [] a4 = new int[]{MAX_WEIGHT,7,MAX_WEIGHT,0,2,MAX_WEIGHT,3,MAX_WEIGHT,MAX_WEIGHT}; int [] a5 = new int[]{MAX_WEIGHT,5,1,2,0,3,6,9,MAX_WEIGHT}; int [] a6 = new int[]{MAX_WEIGHT,MAX_WEIGHT,7,MAX_WEIGHT,3,0,MAX_WEIGHT,5,MAX_WEIGHT}; int [] a7 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,3,6,MAX_WEIGHT,0,2,7}; int [] a8 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,9,5,2,0,4}; int [] a9 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,7,4,0}; matrix[0] = a1; matrix[1] = a2; matrix[2] = a3; matrix[3] = a4; matrix[4] = a5; matrix[5] = a6; matrix[6] = a7; matrix[7] = a8; matrix[8] = a9; }
package cn.itcast.grape; import cn.itcast.treeandgrape.Graph; public class JavaDijstra { private final static int MAXVEX = 9;//頂點,之後不須要寫死 private final static int MAXWEING = 65535;//(最大)權重 private int shortTablePath[] = new int[MAXVEX];//存儲V0到某頂點最短路徑的權值和 例:{0,1,5} /** * 獲取一個圖的最短路徑 */ public void shortestPathDijstra(Graph graph) { int min;//最小值 int k = 0;//記錄下標 boolean isgetPath[] = new boolean[MAXVEX];//是否已經拿到了V0到Vm的最短路徑 for (int v = 0; v < graph.getVertexSize(); v++) {//遍歷頂點數量 shortTablePath[v] = graph.getMatrix()[0][v];//得到V0這一行的權值數組 } shortTablePath[0] = 0;//V0到V0的距離是0, 拿到數據後,沒必要往回走 isgetPath[0] = true; for (int v = 1; v < graph.getVertexSize(); v++) {//橫向 min = MAXWEING;//初始化 for (int w = 0; w < graph.getVertexSize(); w++) {//縱向,對找出來的頂點一個一個遍歷 if (!isgetPath[w] && shortTablePath[w] < min) { k = w; min = shortTablePath[w]; } } isgetPath[k] = true; for (int j = 0; j < graph.getVertexSize(); j++) { if (!isgetPath[j] && (min + graph.getMatrix()[k][j] < shortTablePath[j])) { shortTablePath[j] = min + graph.getMatrix()[k][j]; } } } for (int i = 0; i < shortTablePath.length; i++) { System.out.println("V0到V" + i + "的最短路徑爲:" + shortTablePath[i] + "\n"); } } public static void main(String[] args) { Graph graph = new Graph(MAXVEX); graph.createGraph(); JavaDijstra dijstra = new JavaDijstra(); dijstra.shortestPathDijstra(graph); } }
AOV網:在一個表示工程的有向圖中,用頂點表示活動,用弧表示活動之間的優先關係,這樣的有向圖爲頂點表示活動的網,稱爲AOV網(Activity On Vertex)。
AVO網不存在環路
拓撲序列:設G=(V,E)是一個具備n個頂點的有向圖,V中頂點序列V1,V2,......,Vn,知足若從頂點Vi到Vj有一條路徑,則在頂點序列中頂點Vi必在頂點Vj以前,則這樣的頂點序列稱爲一個拓撲序列。
拓撲序列並不惟一
拓撲排序就是構造拓撲序列的過程,當AOV網中不存在環路時,所有頂點都會被輸出。
思想:從AOV網中選擇一個入度爲0的頂點輸出,而後刪除此頂點,並刪除一次頂點爲尾的弧,繼續重複該步驟,直至輸出所有頂點或者AOV網中不存在入度爲0的頂點爲止。
因爲拓撲排序須要刪除頂點,因此使用鄰接表的方式存儲圖會較爲方便
鄰接表的結構不侷限於此,能夠根據實際狀況添加字段,如在拓撲排序中能夠在頂點表中增長入度字段,用於統計每一個頂點的入度狀況。在帶權圖中能夠在邊表中添加weight字段,用於表示每條邊的權值。
package cn.itcast.grape; import java.util.Stack; public class DnGraphTopologic { private int numVertexes; private VertexNode[] adjList;//鄰接頂點的一維數組 public DnGraphTopologic(int numVertexes) { this.numVertexes = numVertexes; } private void createGraph() { VertexNode node0 = new VertexNode(0, "v0"); VertexNode node1 = new VertexNode(0, "v1"); VertexNode node2 = new VertexNode(2, "v2"); VertexNode node3 = new VertexNode(0, "v3"); VertexNode node4 = new VertexNode(2, "v4"); VertexNode node5 = new VertexNode(3, "v5"); VertexNode node6 = new VertexNode(1, "v6"); VertexNode node7 = new VertexNode(2, "v7"); VertexNode node8 = new VertexNode(2, "v8"); VertexNode node9 = new VertexNode(1, "v9"); VertexNode node10 = new VertexNode(1, "v10"); VertexNode node11 = new VertexNode(2, "v11"); VertexNode node12 = new VertexNode(1, "v12"); VertexNode node13 = new VertexNode(2, "v13"); adjList = new VertexNode[numVertexes]; adjList[0] = node0; adjList[1] = node1; adjList[2] = node2; adjList[3] = node3; adjList[4] = node4; adjList[5] = node5; adjList[6] = node6; adjList[7] = node7; adjList[8] = node8; adjList[9] = node9; adjList[10] = node10; adjList[11] = node11; adjList[12] = node12; adjList[13] = node13; node0.firstEdge = new EdgeNode(11); node0.firstEdge.next = new EdgeNode(5); node0.firstEdge.next.next = new EdgeNode(4); node1.firstEdge = new EdgeNode(8); node1.firstEdge.next = new EdgeNode(4); node1.firstEdge.next.next = new EdgeNode(2); node2.firstEdge = new EdgeNode(9); node2.firstEdge.next = new EdgeNode(6); node2.firstEdge.next.next = new EdgeNode(5); node3.firstEdge = new EdgeNode(13); node3.firstEdge.next = new EdgeNode(2); node4.firstEdge = new EdgeNode(7); node5.firstEdge = new EdgeNode(12); node5.firstEdge.next = new EdgeNode(8); node6.firstEdge = new EdgeNode(5); node8.firstEdge = new EdgeNode(7); node9.firstEdge = new EdgeNode(11); node9.firstEdge.next = new EdgeNode(10); node10.firstEdge = new EdgeNode(13); node12.firstEdge = new EdgeNode(9); } /** * 拓撲排序 */ private void topologicalSort() throws Exception { Stack<Integer> stack = new Stack<>(); int count = 0;//計數,看拓撲排序是否是正確 int k = 0; for (int i = 0; i < numVertexes; i++) { if (adjList[i].in == 0) { stack.push(i); } } while (!stack.isEmpty()) { int pop = stack.pop();//彈出棧 System.out.println("頂點:" + adjList[pop].data); count++; for (EdgeNode node = adjList[pop].firstEdge; node != null; node = node.next) {//橫向遍歷 k = node.adjVert;//下標 if (--adjList[k].in == 0) { stack.push(k);//入度爲0,入棧 } } } if (count<numVertexes){ throw new Exception("拓撲排序失敗"); } } //邊表頂點(橫) class EdgeNode { private int adjVert;//下標 private EdgeNode next; private int weight;//全重,先看有沒有權重 public EdgeNode(int adjVert) { this.adjVert = adjVert; } public int getAdjVert() { return adjVert; } public void setAdjVert(int adjVert) { this.adjVert = adjVert; } public EdgeNode getNext() { return next; } public void setNext(EdgeNode next) { this.next = next; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } } //鄰接頂點(縱) class VertexNode { private int in;//入度 private String data; private EdgeNode firstEdge; public VertexNode(int in, String data) { this.in = in; this.data = data; } } public static void main(String[] args) { DnGraphTopologic dnGraphTopologic = new DnGraphTopologic(14); dnGraphTopologic.createGraph(); try { dnGraphTopologic.topologicalSort(); } catch (Exception e) { e.printStackTrace(); } } }