迪傑斯特拉(Dijkstra)演算法求圖中最短路徑
迪傑斯特拉(Dijkstra )演算法:
對於圖G=(V,E),將圖的頂點分為兩組:
頂點集S:已求出的最短路徑的頂點集合(初始為{v0});
頂點集V-S:尚未求出最短路徑的頂點集合(初始為V-{v0} )。
演算法按最短路徑長度的遞增順序逐個將V-S的頂點加入S中,直到所有頂點均被加入S為止。
演算法需藉助輔助陣列dist[N], dist[i]表示目前已經找到的、從開始點v0到終點vi的當前最短路徑的長度。
dist各元素的初值:若從v0到vi存在弧,則dist[i]為弧上的權值;否則dist[i]為∞。
演算法執行過程:
(1)當前下一條長度最短的路徑必為 ( v0, … , vk ),vk滿足如下條件:
dist[k]=Min{dist[i] | vi∈V-S}
求得頂點vk的最短路徑後,將vk加入頂點集S中。
修正:每加入一個新的頂點vk到頂點集S,則對V-S中剩餘的各頂點,多了一個“中轉”結點vk,從而可能多一條“中轉”路徑,新的中轉路徑可能小於原來的路徑,所以需對V-S剩餘的各頂點的最短路徑長度dist[i]進行修正。
(2)如何修正?
原來v0到vi的最短路徑長度為dist[i],加入vk後,以vk為中間頂點的“中轉”路徑長度為:dist[k] + wki,(wki為弧”<”vk, vi>上的權值),若“中轉”路徑長度小於原dist[i](即 dist[k] + wki < dist[i]),則將頂點vi的最短路徑長度修正為“中轉”路徑的長度。
(3)重複上述步驟(1)(2),直到所有頂點均加入S為止。
另外,為了記錄從v0出發到各頂點的最短“路徑”(頂點序列),使用輔助陣列path[ ], path[i]表示當前找到的從開始頂點v0到頂點vi的當前最短路徑頂點序列。
path[N]各元素的初值:如果從v0到vi有弧存在,則path[i]為(v0, vi);否則path[i]為空。
//Dijkstra演算法
#define INFINITY 32768
typedef unsigned int WeightType
typedef WeightType Adjtex
typedef Seqlist VertexSet;
ShortestPath_DJS(AdjMartrix g, int v0, WeightType dist[MAX_VERTEX_NUM],
VertexSet path[MAX_VERTEX_NUM]) {
/*path[i]中存放當前頂點i的最短路徑,是一個線性表。dist[i]中存放頂點i的當前最短路徑長度*/
VertexSet s; /*s為已找到最短路徑的終點集合*/
for(i = 0; i < g.vexnum; i++) {
InitList(&path[i]); /*初始化dist[i]和path[i]*/
dist[i] = g.arcs.[v0][i].adj; /*dist[i]初始放當前頂點i到v0的路徑長度*/
if(dist[i] < INFINITY) { /*如果經過上一步權值存在(路徑存在)*/
AddTail(&path[i], g.vertex[v0]); /*AddTail是表尾新增操作*/
AddTail(&path[i], g.vertex[i]); /*構造從v0到i的路徑序列,儲存在順序表陣列的第i行*/
}
}
InitList(&s);
AddTail(&s, g.vertex[v0]); /*將v0看成第一個已找到最短路徑的終點*/
for(t = 1; t <= g.vexnum - 1; t++) { /*求v0到其餘n-1個頂點額最短路徑(n=g.vexnum)*/
min = INFINITY;
for(i = 0; t <= g.vexnum; i++) {
if(!Member(g.vertex[i], s) && dist[i] < min) {//該點不存在s集合中且該點到v0的路徑存在
k = i; min = dist[i];
}
}
if(min == INFINITY) return; //如果經過上步沒有修改min的值,說明當前頂點到v0沒有路徑 回退
AddTail(&s, g.vertex[k]); //把當前頂點加到s集合中
for(i = 0; i < g.vertex; i++) {
//如果該頂點不在s集合中且路徑存在且該點通過已經加進s集合的點建立的新路徑長度小於原路徑
if(!Member(g.vertex[i], s) && g.arcs[k][i].adj != INFINITY
&& (dist[k] + g.arc[k][i].adj < dist[i]) {
dist[i] = dist[k] + g.arcs[k][i].adj; //修改dist[i]為即最新的最短路徑長度
path[i] = path[k]; //更新路徑
AddTail(&path[i], g.vertex[i]); /*path[i] = path[k]∪{vi}*/
}
}
}
}
知乎:Solo | 微博@從流域到海域