Dijkstra(迪傑斯特拉)算法是典型的最短路徑路由算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點爲中心向外層層擴展,直到擴展到終點爲止(BFS、prime算法都有類似思想)。Dijkstra算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低。
1、算法思想
令G = (V,E)爲一個帶權有向網,把圖中的頂點集合V分成兩組:已求出最短路徑的頂點集合S(初始時S中只有源節點,以後每求得一條最短路徑,就將它對應的頂點加入到集合S中,直到全部頂點都加入到S中);未確定最短路徑的頂點集合V-S。在加入過程中,總保持從源節點v到S中各頂點的最短路徑長度不大於從源節點v到V-S中任何頂點的最短路徑長度。
2、算法描述
(1)S爲已經找到的從v出發的最短路徑的終點集合,它的初始狀態爲空集,那麼從v出發到圖中其餘各頂點(終點)vi(vi∈V-S)可能達到的最短路徑長度的初值爲:
d[i] = arcs[LocateVex(G, v)][i],vi∈V
(2)選擇vj,使得 d[j] = Min{d[i]|vi屬於V-S},vj就是當前求得的一條從v出發的最短路徑的終點。令S=S∪{j};
(3)修改從v出發到集合V-S上任一頂點vk可達的最短路徑長度。如果 d[j] + arcs[j][k] < d[k], 則修改d[k]爲:d[k] = d[j] + arcs[j][k];
(4)重複(2),知道所有頂點都包含在S中,此時得到v到圖上其餘各頂點的最短路徑是依路徑長度遞增的序列。
具體圖例與算法執行步驟:(從A開始,到各節點的最短路徑)
具體執行步驟如下圖所示:
PS:圖片右下角是原作者的博客地址。
3、算法具體實現
[cpp] view plain copy
typedef int PathMatrix; //用於存儲最短路徑序列的頂點下標數組
typedef EdgeType ShortPathTable; //用於存儲到各點最短路徑的權值和
[cpp] view plain copy
/* Dijkstra算法求有向網g的下標爲v0的頂點到其餘頂點下標爲v的最短路徑P[v]及帶權長度D[v] */
/* P[v]的值爲前驅頂點下標,D[v]表示v0到v的最短路徑長度和 */
void ShortestPath_DIJ(Graph *g, int v0, PathMatrix p[], ShortPathTable d[])
{
int i, v, w, k;
EdgeType min;
bool final[MAX_VEX]; /* final[w]=1表示求得頂點V0至Vw的最短路徑 */
//初始化數據
for (v = 0; v < g->vexNum; v++)
{
final[v] = false; //全部頂點初始化爲未知最短路徑狀態
d[v] = g->arc[v0][v]; //將與v0點有連線的頂點加上權值
p[v] = v0; //初始化路徑數組P爲v0
}
d[v0] = 0; //v0至v0的路徑爲0
final[v0] = true; //v0∈S, v0至v0不需要求路徑
//開始主循環,每次求得v0到某個v頂點的最短路徑,並 加入v到集合S
for (i = 0; i < g->vexNum; i++)
{
if (i == v0) continue;
min = INFINITY;
for (w = 0; w < g->vexNum; w++) //尋找V-S中離v0最近的頂點
{
if (!final[w] && d[w] < min)
{
min = d[w]; //下標爲w的頂點離v0更近
v = w;
}
}
//if (v == t) break; //如果只查找到下標爲t的某個頂點
final[v] = true; //下標爲k的頂點併入集合S,即將當前找到了最短路徑的頂點標記爲true
//更新當前最短路徑及距離
for (w = 0; w < g->vexNum; w++)
{
//如果經過v頂點的路徑比現在這條路徑的長度短的話
if (!final[w] && (min + g->arc[v][w] < d[w]))
{
//說明找到了更短的路徑,修改D[w]和P[w]
d[w] = min + g->arc[v][w];
p[w] = v;
}
}
}
}
下面是根據路徑數組PathMatrix得到具體的路徑序列:
[cpp] view plain copy
// 查找從源點v到終點u的路徑,並輸出
void SearchPath(VertexType vex[], PathMatrix *prev,int v, int u)
{
int que[MAX_VEX];
int tot = 0;
que[tot++] = u; //終點u
int tmp = prev[u]; //到頂點下標u的路徑上的上一個頂點下標
while(tmp != v)
{
que[tot++] = tmp;
tmp = prev[tmp]; //到頂點下標tmp的路徑上的上一個頂點下標
}
que[tot] = v;
for(int i = tot; i >= 0; –i)
if(i != 0)
printf(“%c -> “, vex[que[i]]);
else
printf(“%c”, vex[que[i]]);
}
以上面的無向網爲例,運行結果截圖:
dijkstra算法兩個應用題:
HDOJ 1874 暢通工程續,現有解法:www.wutianqi.com/?p=1894
HDOJ 2544 最短路,現有解法:www.wutianqi.com/?p=1892
參考:http://hi.baidu.com/zealot886/item/c8a499ee5795bcddeb34c950
數據結構(C語言版)
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
推薦幾篇搜索算法相關的非常好的博文:
一、A*搜索算法
一(續)、A*,Dijkstra,BFS算法性能比較及A*算法的應用
二、Dijkstra 算法初探 (Dijkstra算法系列4篇文章)
二(續)、徹底理解Dijkstra算法
二(再續)、Dijkstra 算法+fibonacci堆的逐步c實現
二(三續)、Dijkstra 算法+Heap堆的完整c實現源碼