大話數據結構學習筆記 - 圖的最短路徑之Floyd
算法
本文是對網結構最短路徑的另一求法,上一節講的爲Dijkstra
算法,本節將Floyd
算法, 有關於最短路徑的講解也在上一節。
Floyd
算法
算法簡介
弗洛伊德Floyd
算法也是一種在給定的加權圖中求最短路徑的算法,求的所有頂點到所有頂點的時間複雜度爲 , 是由1978年的圖靈獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名。
基本思想
首先定義兩個二維數組D[MAXVEX][MAXVEX]
和P[MAXVEX][MAXVEX]
,D
數組代表頂點到頂點的最短路徑權值和矩陣, P
代表對應頂點的最小路徑前驅矩陣。 初始時,將矩陣D
中頂點D[v][w]
設置爲頂點v
到頂點w
的權值,若兩頂點不相連,則D[v][w] = INF
。接下來對矩陣D
更新, 如果D[v][w] > D[v][k] + D[k][w]
, k
表示v、w
兩頂點通過中轉頂點,該表達式表示通過中轉頂點的權值和較小時,更新v、w
權值和。下面通過實例進行演示
算法圖解
初始狀態:初始化P
和D
矩陣, D
表示頂點到頂點的權值, P
表示頂點v
到頂點w
的最短路徑。若頂點之間直接相連,則D
矩陣值爲權值,否則爲無窮大。
第一步: 首先以第一個頂點v0
爲中轉點, 即所有的頂點都經過v0
中轉,計算是否有最短路徑的變化,結果沒有
第二步: 以v1
頂點爲中轉點,即所有頂點都經過v1
中轉, 可以看到,D[0][2] > D[0][1] + D[1][2]
, 即表示以v1
爲中轉點,頂點v0
到v2
的權值和變小了,即D[0][2] = 4
, 同理可得D[0][3] = 8, D[0][4] = 6
, 然後更新D
矩陣和P
矩陣
第三步: 接下來,依次以每個頂點作爲中轉點, 得到以每個頂點做爲中轉點後的權值, 得到最終的矩陣D
和矩陣P
代碼
無向圖結構
#define MAXVEX 9
#define INF 65535
typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];
typedef struct
{
int vexs[MAXVEX];
int arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
算法
/* Floyd 算法, 求網圖 G 中各頂點 v 到其餘頂點 w 的最短路徑 P[v][w] 及帶權長度 D[v][w] */
void ShortestPath_Floyd(MGraph G, Patharc *P, ShortPathTable *D) {
/* 初始化 D 與 P */
for (int v = 0; v < G.numVertexes; ++v) {
for (int w = 0; w < G.numVertexes; ++w) {
(*D)[v][w] = G.arc[v][w]; /* D[v][w] 值即爲對應頂點間的權值 */
(*P)[v][w] = w; /* 初始化 P */
}
}
for (int k = 0; k < G.numVertexes; ++k) {
for (int v = 0; v < G.numVertexes; ++v) {
for (int w = 0; w < G.numVertexes; ++w) {
if ((*D)[v][w] > (*D)[v][k] + (*D)[k][w]) {
/* 如果經過下標爲 k 的頂點路徑比原兩點間路徑更短 */
(*D)[v][w] = (*D)[v][k] + (*D)[k][w]; /* 將當前兩點間權值設爲更小的一個 */
(*P)[v][w] = (*P)[v][k]; /* 路徑設置爲經過下標爲 k 的頂點 */
}
}
}
}
}
打印各頂點間的最短路徑
/* 打印各頂點間的最短路徑 */
void ShowShortestPath(MGraph G, Patharc *P, ShortPathTable *D)
{
for(int v = 0; v < G.numVertexes; ++v)
{
for(int w = v + 1; w < G.numVertexes; ++w)
{
printf("v%d-v%d weight: %d ",v,w,(*D)[v][w]);
int k = (*P)[v][w]; /* 獲得第一個路徑頂點下標 */
printf(" path: %d",v); /* 打印源點 */
while (k != w) /* 如果路徑頂點下標不是終點 */
{
printf(" -> %d",k); /* 打印路徑頂點 */
k = (*P)[k][w]; /* 獲得下一個路徑頂點下標 */
}
printf(" -> %d\n",w); /* 打印終點 */
}
printf("\n");
}
}
源碼
結語
關於圖的最短路徑的兩種方法都已整理,繼續加油go go go