【1】最短路徑 html
最短路徑?別亂想哈,其實就是字面意思,一個帶邊值的圖中從某一個頂點到另一個頂點的最短路徑。 ios
官方定義:對於內網圖而言,最短路徑是指兩頂點之間通過的邊上權值之和最小的路徑。算法
而且咱們稱路徑上的第一個頂點爲源點,最後一個頂點爲終點。數組
因爲非內網圖沒有邊上的權值,所謂的最短路徑實際上是指兩頂點之間通過的邊數最少的路徑。 ide
別廢話了!整點實際的哈,你能很快計算出下圖中由源點V0到終點V8的最短路徑嗎? 測試
【2】迪傑斯特拉算法 spa
迪傑斯特拉算法是按路徑長度遞增的次序產生最短路徑的思路求解。 3d
具體算法及其詳細講解以下:調試
閱讀程序前,先要搞明白幾個數組做用: code
final[w]=1; 表示V0到Vw頂點已經有最短路徑的結果
ShortPathTable[w]; 表示V0到Vw頂點的最短路徑權值和
Pathmatirx[w]; 表示V0到Vw頂點的前驅頂點下標值
開始調用算法前,咱們須要爲案例圖建立鄰接矩陣圖,以下所示:
(1)程序開始運行,final數組是爲了標記V0到某頂點是否已經求得最短路徑。
若是V0到Vw已經有結果,那麼final[w]=1;
(2)第5~10行,是對數據初始化工做。 此時final數組均賦值爲0,表示全部點均未求得最短路徑。
D數組爲 {0,1,5,65515,65535,65535,65535,65535,65535}。由於V0與V1和V2的邊權值爲1和5。
P數組全爲0,表示目前沒有路徑。
(3)第11行,表示V0至V0路徑爲0。
第12行,表示V0點到V0點已經求得最短路徑,所以final[0]=1。
此時final數組爲 {1,0,0,0,0,0,0,0,0},此時整個初始化工做完成。
(4)第13~33行爲主循環,每次循環求得V0與一個頂點的最短路徑。除去V0,所以索引從1開始。
(5)第15~23行,先令min爲65535的極大值,經過w控制循環,與D[w]比較找到最小值爲min=1,同時肯定k=1。
(6)第24行,由k=1可知與V0最近的頂點是V1,而且由D[1]=1知道此時V0到V1的最短路徑是1。
所以再將對應的final[1]設置爲1。此時final數組爲 {1,1,0,0,0,0,0,0,0}
(7)第25~32行是一循環,此循環甚爲關鍵。
它的目的是在剛纔已經找到V0與V1的最短路徑基礎之上,對V1與其它頂點的邊進行計算,獲得V0與它們的當前最短距離,如圖所示:
由於min=1,因此D[2]=5再也不是V0到V2的最短路徑,如今D[2]=V0->V1->V2=min+3=4, D[3]=V0->V1->V3=min+7=8,
D[4]=V0->V1->V4=min+5=6,因而D數組當前值爲 {0,1,4,8,6,65535,65535,65535,65535}。
而P[2]=1,P[3]=1,P[4]=1,其表示V0到V2,V3,V4點的最短路徑它們的前驅均是V1。
此時P數組爲 {0,0,1,1,1,0,0,0,0}。
(8)新一輪循環,此時i=2。第15~23行,對w循環,注意由於final[0]=1和final[1]=1,由第18行的!final[w]可知:
V0與V1並不參與最小值的獲取。經過循環比較,找到最小值min=4,k=2。
(9)第24行,由k=2,表示已經求出V0到V2的最短路徑,而且由D[2]=4知道最短路徑距離爲4。
所以將V2對應的final[2]設置爲1,此時final數組爲 {1,1,1,0,0,0,0,0,0}。
(10)第25~32行,在剛纔已經找到V0與V2的最短路徑的基礎上,對V2與其它頂點的邊進行計算,獲得V0與它們的最短距離。
如圖所示:
由於min=4,因此D[4]=6再也不是V0到V4的最短距離,如今D[4]=V0->V2->V4=min+1=5,D[5]=V0->V2->V5=min+7=11。
所以D數組當前值爲 {0,1,4,8,5,11,65535,65535,65535,65535}。
而本來P[4]=1,此時P[4]=2,P[5]=2,它表示的意思是V0到V4和V5的最短路徑前驅均爲V2。
此時P數組爲 {0,0,1,1,2,2,0,0,0}。
(11)從新再開始一輪循環,此時i=3。第15~23行,經過對w循環比較找到最小值min=5,k=4。
(12)第24行,由k=4表示已經求出V0到V4的最短路徑,而且由D[4]=5知道最短路徑距離爲5。
所以將V4對應的final[4]設置爲1。此時final數組爲 {1,1,1,0,1,0,0,0,0}。
(13)第25~32行,對V4與其它頂點的邊值進行計算,獲得V0與它們的當前最短距離,如圖所示:
由於min=5,因此D[3]=8再也不是V0到V3的最短路徑,如今D[3]=V0->V4->V3=min+2=7,同理:
D[5]=V0->V4->V5=min+3=8,D[6]=V0->V4->V6=min+6=11,
D[7]=V0->V4->V7=min+9=14,所以,D數組當前值爲 {0,1,4,7,5,8,11,14,65535}。
而本來P[3]=1,此時P[3]=4,本來P[5]=2,此時P[5]=4。
另外P[6],P[7]=4,它表示V0到V3,V5,V6,V7點的最短路徑它們的前驅是V4。
此時P數組值爲 {0,0,1,4,2,4,4,4,0}。
(14)以後的循環徹底相似。獲得最終的結果,如圖所示:
此時final數組爲 {1,1,1,1,1,1,1,1,1},它表示全部的頂點均完成了最短路徑的查找工做。
此時D數組爲 {0,1,4,7,5,8,10,12,16},它表示V0到各個頂點的最短路徑數,好比D[8]=1+3+1+2+3+2+4=16。
此時的P數組爲 {0,0,1,4,2,4,3,6,7}:
這個P數組值可能難理解一些。好比P[8]=7,它表示要查看V0到V8的最短路徑時,頂點V8的前驅是V7;
再由P[7]=6表示要查看V0到V7的最短路徑時,頂點V7的前驅是V6,同理,P[6]=3表示V6的前驅是V3。
這樣就能夠獲得:V0到V8最短路徑爲V8<-V7<-V6<-V3<-V4<-V2<-V1<-V0
即就是: V0->V1->V2->V4->V3->V6->V7->V8。
【3】算法實現
實現代碼以下:
1 #include <iostream> 2 #include "SeqList.h" 3 #include "Stack.h" 4 #include <iomanip> 5 using namespace std; 6 7 #define INFINITY 65535 8 9 template<class NameType, class DistType> 10 class Graph 11 { 12 private: 13 SeqList<NameType> Vertices; 14 DistType **Edges; 15 int nVer, nEdges; 16 17 public: 18 Graph() 19 : Edges(NULL) 20 , nEdges(0) 21 , nVer(0) 22 {} 23 ~Graph() 24 {} 25 26 public: 27 int GetVer() const 28 { 29 return nVer; 30 } 31 32 istream & operator>>(istream &in) 33 { 34 int v, u, value; 35 int i, j; 36 NameType item; 37 cout << "請輸入頂點的個數: " << endl; 38 in >> nVer; 39 cout << "請輸入頂點的數據信息: " << endl; 40 for (i = 0; i < nVer; ++i) 41 { 42 in >> item; 43 Vertices.push_back(item); // 保存所有頂點 44 } 45 /////二維數組的建立並初始化 46 Edges = new DistType*[nVer]; // DistType *ar[10]; 47 for (i = 0; i < nVer; ++i) 48 { 49 Edges[i] = new DistType[nVer]; 50 for (j = 0; j < nVer; ++j) 51 { 52 Edges[i][j] = 0; 53 } 54 } 55 cout << "請輸入邊的個數: " << endl; 56 in >> nEdges; 57 cout << "請輸入邊的信息:" << endl; 58 for (i = 0; i < nEdges; ++i) 59 { 60 in >> v >> u >> value; 61 Edges[v][u] = value; 62 Edges[u][v] = value; 63 } 64 return in; 65 } 66 ostream & operator<<(ostream &out) const 67 { 68 int i, j; 69 out << "頂點信息 " << endl; 70 for (i = 1; i <= nVer; ++i) 71 { 72 out << Vertices[i] << setw(5); 73 } 74 out << endl; 75 out << "矩陣信息:" << endl; 76 out << setw(10); 77 for (i = 1; i <= nVer; ++i) 78 { 79 out << Vertices[i] << setw(5); 80 } 81 out << endl; 82 for (i = 0; i < nVer; ++i) 83 { 84 out << Vertices[i+1] << setw(5); 85 for (j = 0; j < nVer; ++j) 86 { 87 if (0 == Edges[i][j] && i != j) 88 Edges[i][j] = INFINITY; 89 cout << Edges[i][j] << setw(5); 90 } 91 out << endl; 92 } 93 out << endl; 94 95 return out; 96 } 97 // 迪傑斯特拉算法實現 98 void ShortestPath_Dijkstra(int v0, int* final, int*p, int *D) 99 { 100 int v, w, k, min; 101 // 初始化數據 102 for (v = 0; v < nVer; ++v) 103 { 104 final[v] = 0; // 所有頂點初始化爲未知對短路徑狀態 105 D[v] = Edges[v0][v]; //將與V0點有連線的頂點加上權值 106 p[v] = 0; // 初始化路徑數組p爲0 107 } 108 D[v0] = 0; // V0至V0路徑爲0 109 final[v0] = 1; // final[W]=1表示V0至V0不須要求路徑 110 // 開始主循環,每次求得V0到某個V頂點的最短路徑 111 for (v = 1; v < nVer; ++v) 112 { 113 min = INFINITY; // 當前所知離V0頂點最近距離 114 for (w = 0; w < nVer; ++w) // 尋找離V0最近的頂點 115 { 116 if (!final[w] && D[w] < min) 117 { 118 min = D[w]; // w頂點離V0頂點更近 119 k = w; 120 } 121 } 122 123 final[k] = 1; // 將目前找到的最近的頂點置爲1 124 for (w = 0; w < nVer; ++w) // 修正當前最短路徑距離 125 { 126 // 若是通過V頂點的路徑比如今這條路徑的長度短的話 127 if (!final[w] && (min + Edges[k][w] < D[w])) 128 { 129 // 說明找到了最短的路徑,修改D[w] 和 p[w] 130 D[w] = min + Edges[k][w]; // 修改當前路徑長度 131 p[w] = k; 132 } 133 } 134 } 135 } 136 }; 137 138 template<class NameType, class DistType> 139 istream & operator>>(istream &in, Graph<NameType,DistType> &g) 140 { 141 g >> in; 142 return in; 143 } 144 145 template<class NameType, class DistType> 146 ostream & operator<<(ostream &out, const Graph<NameType,DistType> &g) 147 { 148 g << out; 149 return out; 150 } 151 152 void main() 153 { 154 Graph<char, int> myg; 155 cin >> myg; 156 cout << "打印全部輸入信息:" << endl; 157 cout << myg << endl; 158 cout << "求最短路徑....." << endl; 159 int numVer = myg.GetVer(); 160 int* pFinal = new int[numVer]; 161 int* pPathmatirx = new int[numVer]; 162 int* pShortPath = new int[numVer]; 163 myg.ShortestPath_Dijkstra(0, pFinal, pPathmatirx, pShortPath); 164 cout << "打印各頂點最短路徑標記數組值:" << " "; 165 for (int i = 0; i < numVer; ++i) 166 { 167 cout << pFinal[i] << " "; 168 } 169 cout << endl; 170 cout << "打印最短路徑數組值:" << " "; 171 for (int i = 0; i < numVer; ++i) 172 { 173 cout << pShortPath[i] << " "; 174 } 175 cout << endl; 176 cout << "打印最短路徑前驅數組值:" << " "; 177 for (int i = 0; i < numVer; ++i) 178 { 179 cout << pPathmatirx[i] << " "; 180 } 181 cout << endl; 182 cout << "打印V0到各個頂點最短路徑值以及路徑信息:" << endl; 183 SeqStack<int> sQ; 184 for (int i = 1; i < numVer; ++i) 185 { 186 cout << "V0~V" << i << ": " << pShortPath[i] << endl; 187 188 sQ.Push(pPathmatirx[i]); 189 int n = 0; 190 while (sQ.GetTop(n) && n != 0) 191 { 192 sQ.Push(pPathmatirx[n]); 193 } 194 195 while (!sQ.IsEmpty()) 196 { 197 int m = 0; 198 sQ.Pop(m); 199 cout << "V" << m << "->"; 200 } 201 cout << "V" << i << endl; 202 } 203 delete []pFinal; 204 delete []pPathmatirx; 205 delete []pShortPath; 206 pFinal = NULL; 207 pPathmatirx = NULL; 208 pShortPath = NULL; 209 } 210 // 備註: 211 // 最短路徑迪傑斯特拉算法實現 212 // 整理於2013-12-04 213 // 測試輸入程序爲: 214 /* 215 請輸入頂點的個數: 216 9 217 請輸入頂點的數據信息: 218 A B C D E F G H I 219 請輸入邊的個數: 220 16 221 請輸入邊的信息: 222 0 1 1 223 0 2 5 224 1 2 3 225 1 3 7 226 1 4 5 227 2 4 1 228 2 5 7 229 3 4 2 230 3 6 3 231 4 5 3 232 4 6 6 233 4 7 9 234 5 7 5 235 6 7 2 236 6 8 7 237 7 8 4 238 打印全部輸入信息: 239 頂點信息 240 A B C D E F G H I 241 矩陣信息: 242 A B C D E F G H I 243 A 0 1 5655356553565535655356553565535 244 B 1 0 3 7 565535655356553565535 245 C 5 3 065535 1 7655356553565535 246 D65535 765535 0 265535 36553565535 247 E65535 5 1 2 0 3 6 965535 248 F6553565535 765535 3 065535 565535 249 G655356553565535 3 665535 0 2 7 250 H65535655356553565535 9 5 2 0 4 251 I655356553565535655356553565535 7 4 0 252 253 254 求最短路徑..... 255 打印各頂點最短路徑標記數組值: 1 1 1 1 1 1 1 1 1 256 打印最短路徑數組值: 0 1 4 7 5 8 10 12 16 257 打印最短路徑前驅數組值: 0 0 1 4 2 4 3 6 7 258 打印V0到各個頂點最短路徑值以及路徑信息: 259 V0~V1: 1 260 V0->V1 261 V0~V2: 4 262 V0->V1->V2 263 V0~V3: 7 264 V0->V1->V2->V4->V3 265 V0~V4: 5 266 V0->V1->V2->V4 267 V0~V5: 8 268 V0->V1->V2->V4->V5 269 V0~V6: 10 270 V0->V1->V2->V4->V3->V6 271 V0~V7: 12 272 V0->V1->V2->V4->V3->V6->V7 273 V0~V8: 16 274 V0->V1->V2->V4->V3->V6->V7->V8 275 */
關於實現代碼中的SeqList.h文件和Stack.h文件從隨筆《順序表》和《棧》中查找拷貝一份便可。調試環境爲VS2010。
Good Good Study, Day Day Up.
順序 選擇 循環 總結