最短路径 - 迪杰斯特拉(Dijkstra)算法
對于網圖來說,最短路徑,是指兩頂點之間經過的邊上權值之和最少的路徑,并且我們稱路徑上的第一個頂點為源點,最后一個頂點為終點。最短路徑的算法主要有迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd)算法。本文先來講第一種,從某個源點到其余各頂點的最短路徑問題。
這是一個按路徑長度遞增的次序產生最短路徑的算法,它的大致思路是這樣的。
比如說要求圖7-7-3中頂點v0到v1的最短路徑,顯然就是1。由于頂點v1還與v2,v3,v4連線,所以此時我們同時求得了v0->v1->v2 = 1+3 = 4, v0->v1->v3 = 1 +7 = 8, v0->v1->v4 = 1+5 = 6。
現在我們可以知道v0到v2的最短距離為4而不是v0->v2 直接連線的5,如圖7-7-4所示。由于頂點v2還與v4,v5連線,所以同時我們求得了v0->v2->v4其實就是v0->v1->v2->v4 = 4+1=5,v0->v2->v5 = 4+7 = 11,這里v0->v2我們用的是剛才計算出來的較小的4。此時我們也發現v0->v1->v2->v4 = 5要比v0->v1->v4 = 6還要小,所以v0到v4的最短距離目前是5,如圖7-7-5所示。
當我們要求v0到v3的最短路徑時,通向v3的三條邊,除了v6沒有研究過外,v0->v1->v3 = 8, 而v0->v4->v3 = 5 +2 = 7,因此v0到v3的最短路徑為7,如圖7-7-6所示。
如上所示,這個算法并不是一下子就求出來v0到v8的最短路徑,而是一步步求出它們之間頂點的最短距離,過程中都是基于已經求出的最短路徑的基礎上,求得更遠頂點的最短路徑,最終得到想要的結果。
程序代碼如下:(改編自《大話數據結構》)
?
C++ Code?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ? | #include<iostream> using?namespace?std; #define?MAXEDGE?20 #define?MAXVEX?20 #define?INFINITY?65535 typedef?struct { ????int?vexs[MAXVEX]; ????int?arc[MAXVEX][MAXVEX]; ????int?numVertexes,?numEdges; }?MGraph; typedef?int?PathArc[MAXVEX]; typedef?int?ShortPathTable[MAXVEX]; /*?構建圖?*/ void?CreateMGraph(MGraph?*G) { ????int?i,?j; ????/*?printf("請輸入邊數和頂點數:");?*/ ????G->numEdges?=?16; ????G->numVertexes?=?9; ????for?(i?=?0;?i?<?G->numVertexes;?i++)/*?初始化圖?*/ ????{ ????????G->vexs[i]?=?i; ????} ????for?(i?=?0;?i?<?G->numVertexes;?i++)/*?初始化圖?*/ ????{ ????????for?(?j?=?0;?j?<?G->numVertexes;?j++) ????????{ ????????????if?(i?==?j) ????????????????G->arc[i][j]?=?0; ????????????else ????????????????G->arc[i][j]?=?G->arc[j][i]?=?INFINITY; ????????} ????} ????G->arc[0][1]?=?1; ????G->arc[0][2]?=?5; ????G->arc[1][2]?=?3; ????G->arc[1][3]?=?7; ????G->arc[1][4]?=?5; ????G->arc[2][4]?=?1; ????G->arc[2][5]?=?7; ????G->arc[3][4]?=?2; ????G->arc[3][6]?=?3; ????G->arc[4][5]?=?3; ????G->arc[4][6]?=?6; ????G->arc[4][7]?=?9; ????G->arc[5][7]?=?5; ????G->arc[6][7]?=?2; ????G->arc[6][8]?=?7; ????G->arc[7][8]?=?4; ????for(i?=?0;?i?<?G->numVertexes;?i++) ????{ ????????for(j?=?i;?j?<?G->numVertexes;?j++) ????????{ ????????????G->arc[j][i]?=?G->arc[i][j]; ????????} ????} } /*??Dijkstra算法,求有向網G的pos頂點到其余頂點v的最短路徑P[v]及帶權長度D[v]?*/ /*??P[v]的值為前驅頂點下標,D[v]表示pos到v的最短路徑長度和?*/ /*??pos?取值?0~MG.numVertexs-1?*/ void?ShortestPath_Dijkstra(MGraph?MG,?int?pos,?PathArc?P,?ShortPathTable?D) { ????int?v,?w,?k,?min; ????int?final[MAXVEX];/*?final[w]=1表示求得頂點pos至w的最短路徑?*/ ????for?(v?=?0;?v?<?MG.numVertexes;?v++) ????{ ????????final[v]?=?0;/*?全部頂點初始化為未知最短路徑狀態?*/ ????????D[v]?=?MG.arc[pos][v];/*?將與pos點有連線的頂點加上權值?*/ ????????P[v]?=?0;/*?初始化路徑數組P為0??*/ ????} ????D[pos]?=?0;?/*說明源點pos沒有到自身的路徑?*/ ????P[pos]?=?-1;?/*?-1表示自身無前驅頂點*/ ????final[pos]?=?1;/*?pos至pos不需要求路徑?*/ ????/*?開始主循環,每次求得pos到某個v頂點的最短路徑?*/ ????for?(v?=?1;?v?<?MG.numVertexes;?v++) ????{ ????????min?=?INFINITY;/*?當前所知離pos頂點的最近距離?*/ ????????for?(w?=?0;?w?<?MG.numVertexes;?w++)/*?尋找離pos最近的頂點?*/ ????????{ ????????????if?(!final[w]?&&?D[w]?<?min) ????????????{ ????????????????k?=?w; ????????????????min?=?D[w];/*?w頂點離pos頂點更近?*/ ????????????} ????????} ????????final[k]?=?1;/*?將目前找到的最近的頂點置為1?*/ ????????for?(w?=?0;?w?<?MG.numVertexes;?w++)/*?修正當前最短路徑及距離?*/ ????????{ ????????????if?(!final[w]?&&?(min?+?MG.arc[k][w]?<?D[w])) ????????????{ ????????????????/*??說明找到了更短的路徑,修改D[w]和P[w]?*/ ????????????????D[w]?=?min?+?MG.arc[k][w];/*?修改當前路徑長度?*/ ????????????????P[w]?=?k; ????????????} ????????} ????} ????/*?結束循環,若P[w]?=?0;說明頂點w的前驅為pos?*/ } int?main(void) { ????MGraph?MG; ????PathArc?P; ????ShortPathTable?D; ????int?i,?j,?pos?=?2; ????CreateMGraph(&MG); ????ShortestPath_Dijkstra(MG,?pos,?P,?D); ????cout?<<?"逆序最短路徑如下:"?<<?endl; ????for?(i?=?8;?i?>=?0;?i--) ????{ ????????j?=?i; ????????while?(P[j]?!=?-1?&&?P[j]?!=?0) ????????{ ????????????cout?<<?"v"?<<?j?<<?"<-"?<<?"v"?<<?P[j]?<<?"??"; ????????????j?=?P[j]; ????????} ????????cout?<<?"v"?<<?j?<<?"<-"?<<?"v"?<<?pos?<<?"??"; ????????cout?<<?endl; ????} ????cout?<<?endl; ????return?0; } |
其中CreateMGraph函數創建出來的鄰接矩陣如圖7-7-7所示。
相信經過上面的分析,大家可以自己進行循環跑程序分析了,循環結束后final = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }表示所有頂點均完成了最短路徑的查找工作。此時D = { 4, 3, 0, 3, 1, 4, 6, 8, 12 }, 注意我們在前面說過Dijkstra算法可以求某個源點到其他頂點的最短路徑,現在我們上面程序中給出的pos = 2, 即源點為v2, 所以D[2] = 0 表示沒有到自身的路徑。D數組表示v2到各個頂點的最短路徑長度,比如D[8] =1+2 + 3 + 2 + 4 = 12。此時P = { 1, 0, -1, 4, 0, 4, 3, 6, 7 }, 可以這樣來理解,P[2] = -1 表示v2沒有前驅頂點,P[1] = P[4] = 0 表示v1和v4的前驅頂點為源點v2。再比如P[8] = 7,表示v8的前驅是v7;再由P[7] = 6,表示v7的前驅是v6; P[6] = 3 表示v6的前驅是v3, 這樣就可以得到v2 到 v8的最短路徑為v2->v4->v3->v6->v7->v8,從上面的程序輸出也可以驗證我們的推測。
其實最終返回的數組D和數組P,是可以得到v2到任意一個頂點的最短路徑和路徑長度的,也就是說我們通過Dijkstra算法解決了從某個源點到其余各頂點的最短路徑問題。從循環嵌套可以得到此算法的時間復雜度為O(n^2),如果我們要得到任一頂點到其余頂點的最短路徑呢?最簡單的辦法就是對每個頂點都當作源點進行一次Dijkstra算法,等于在原有算法的基礎上,再來一次循環,此時整個算法的時間復雜度就為O(n^3)。
總結
以上是生活随笔為你收集整理的最短路径 - 迪杰斯特拉(Dijkstra)算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 虚析构函数? vptr? 指针偏移?多态
- 下一篇: (批量)备份github仓库到本地