最短路徑算法在生活中有極其重要的意義與運用,如高鐵、地鐵的路線規劃問題,最近學習了迪傑斯特拉算法,頗有感慨,遂成一篇筆記以記之。
以鄰接矩陣爲存儲結構,如下圖所示:
拓撲結構圖如下:
求v0到v8的最短路徑,其實思想比較簡單,蘊含着貪心法的思想,它並不是一下子求出v0到v8的最短路徑,而是先求出v0到v1的最短路徑,再求出v2到v3的最短路徑,過程就是基於已經求出的最短路徑的基礎上,求出更遠拓撲點的最短路徑,最終得出結果;
初始時d,p,final數組的值如下:
d: 0 1 5 65535 65535 65535 65535 65535 65535
p: 0 0 0 0 0 0 0 0 0
final: 1 0 0 0 0 0 0 0 0
代碼如下:
#define MAXVEX 9
#define INFINITY 65535 //定義兩個宏,主要是便於以後修改數據
typedef int Patharc[MAXVEX];//用於存儲最短路徑下標的數組
typedef int ShortPathTable[MAXVEX];//用於存儲到各點的最短路徑權值之和
void shortpath_dj(Mgraph g,int v0,Patharc *p,ShortPathTable *d)
{
int v,w,k,min;
int final[MAXVEX];//final[w]表示已經求得頂點V0到Vw的最短路徑,其實就是一個標記數組;
//初始化數據
for(v=0;v<.num;v++)
{
final[v]=0; //全部頂點初始化爲未找到最短路徑;
(*d)[v]=g.arc[v0][v]; //將和v0點有連線的頂點加上權值;這時初始化完成之後*d指向的數組內容即爲鄰接表的第一行內容,圖中的無窮大全部用65535替代;
(*p)[v]=0; //初始化路徑數組p爲0;
}
(*d)[v0]=0; //v0到v0的的路徑爲0;
final[v0]=1; //v0到v0不需要求路徑;
//開始主循環,每次求出v0到某一個頂點的最短路徑;
for(v=1;v<g.num;v++)
{
min=INFINITY;
for(w=0;w<g.num;w++)
{
if(!final[w]&&(*d)[w]<min)
{
k=w;
min=(*d)[w];
}
}
final[k]=1; //表示目前找到的最近頂點下標所對應的內容置1,即代表找到了v0到該點的最短路徑;
}
//修正當前的最短路徑以及距離;
for(w=0;w<g.num;w++)
{
//如果經過v頂點的路徑比現在這條路徑的長度短時,就將其覆蓋;
if(!final[w]&&(min+g.arc[k][w]<(*d)[w]))
{
(*d)[w]=min+g.arc[k][w]; //修改當前路徑的長度,其實(*d)就是一個臨時數組,用來不斷去更好地取值,這也是貪心法的表現,也可以說這個數組喜新厭舊哈;
(*p)[w]=k; //*p你也可以理解爲是用來存放前驅結點的數組,具有雙重含義,就像現實生活中人們說話有時也有兩層意思差不多。比如(*p)[2]內容爲1,就表示v2頂點的前驅是v1!
}
}
}
每次循環之後,三個數組的值都會相應的變化,最終d,p,final三個輔助數組的值如下,大家可以順着程序推演一下,很容易就可以推出,也將很好的理解dj算法原理:
d: 0 1 4 7 5 8 10 12 16
p: 0 0 1 4 2 4 3 6 7
final: 1 1 1 1 1 1 1 1 1
看似複雜的算法也就是通過一步步的組合而成,仔細分析就可得其精髓。