數據結構圖之三(最短路徑--迪傑斯特拉算法)

【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  */
View Code

 關於實現代碼中的SeqList.h文件和Stack.h文件從隨筆《順序表》和《》中查找拷貝一份便可。調試環境爲VS2010。

 

Good  Good  Study, Day  Day Up.

順序  選擇  循環  總結

相關文章
相關標籤/搜索