迪傑斯特拉算法之生活中的最短路徑問題求解原理

最短路徑算法在生活中有極其重要的意義與運用,如高鐵、地鐵的路線規劃問題,最近學習了迪傑斯特拉算法,頗有感慨,遂成一篇筆記以記之。
以鄰接矩陣爲存儲結構,如下圖所示:
在這裏插入圖片描述
拓撲結構圖如下:在這裏插入圖片描述

求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

看似複雜的算法也就是通過一步步的組合而成,仔細分析就可得其精髓。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章