Dijkstra算法(鄰接矩陣存儲)


首先我們需要熟悉Dijkstra算法的原理:

某個源點到其余各頂點的最短路徑,即單源點最短路徑。單源點最短路徑是指:給定帶權有向圖G和源點v,求從v到G中其余各頂點的最短路徑。迪傑斯特拉(Dijkstra)提出了按路徑長度遞增的順序產生各頂點的最短路徑算法。 

該算法的基本思想是: 

(1)設置兩個頂點的集合S和T=V-S,集合S中存放已找到最短路徑的頂點,集合T存放當前還未找到最短路徑的頂點; 

(2)初始狀態時,集合S中只包含源點v0; 

(3)從集合T中選取到某個頂點vi(要求vi到v0的路徑長度最小)加入到S中; 

(4)S中每加入一個頂點vi,都要修改頂點v0到T中剩余頂點的最短路徑長度值,它們的值為原來值與新值的較小者,新值是vi的最短路徑長度加上vi到該頂點的路徑長度; 

(5)不斷重復(3)和(4),直到S包含全部頂點。

算法的代碼實現很巧妙:

1.首先函數里面運用數組D[n]表示源點到節點n的最短距離,s[n]表示某一節點n是否已經進入集合S,如果進入則將s[i]置為1.P[n]表示當前節點n的前驅節點(用來輸出路徑)。

2.在開始遍歷之前,首先給數組D[n]賦值為源點到該點的距離,這樣便能第一次找到源點到相鄰節點的最短距離(D[i]=C[v1][i];)。

3.下面找出最短距離:

if((!S[j])&&(D[j]<min))
{
min=D[j];
k=j;
}

4.更新各節點的最短距離:

for(j=0;j<n;j++)
{
if((!S[j])&&(D[j]>D[k]+C[k][j]))//調整各節點(未進入集合S)的距離值
{
D[j]=D[k]+C[k][j]; //修改藍點j+1的距離
P[j]=k+1; //k+1是j+1的前趨
}
}

4.代碼實現:

  1 #include<stdio.h>
  2 #define maxsize 1000  //表示兩點間不可達,距離為無窮遠
  3 #define n 7  //結點的數目
  4 void dijkstra(int C[][n],int v);//求原點v到其余頂點的最短路徑及其長度
  5 void main()
  6 {
  7   
  8   //對鄰接矩陣進行賦值,沒有直接連通的賦值為maxsize
  9   int C[n][n]=
 10   {
 11      {maxsize,13,8,maxsize,30,maxsize,32},
 12      {maxsize,maxsize,maxsize,maxsize,maxsize,9,7},
 13      {maxsize,maxsize,maxsize,5,maxsize,maxsize,maxsize},
 14      {maxsize,maxsize,maxsize,maxsize,6,maxsize,maxsize},
 15      {maxsize,maxsize,maxsize,maxsize,maxsize,2,maxsize},
 16      {maxsize,maxsize,maxsize,maxsize,maxsize,maxsize,17},
 17      {maxsize,maxsize,maxsize,maxsize,maxsize,maxsize,maxsize}
 18   },v=1,i,j;
 19  
 20  dijkstra(C,v);//迪傑斯特拉算法
 21  
 22 }
 23 void dijkstra(int C[][n],int v)//求原點v到其余頂點的最短路徑及其長度
 24 {
 25  
 26  
 27  int D[n];//用來存儲從起點到某一節點的最短距離
 28  int P[n],S[n];//p[n]表示某一節點的父親,s[n]相當於標志數組
 29  int i,j,k,v1,pre;
 30  int min,max=maxsize,inf=1200;
 31  v1=v-1;//節點號和存儲的數目差1
 32  
 33  
 34  
 35  for(i=0;i<n;i++)
 36  {
 37   D[i]=C[v1][i];   //置初始距離值
 38   if(D[i]!=max) //說明存在邊
 39    P[i]=v;//把父親置為v
 40   else
 41    P[i]=0;//否則父親置為0
 42  }
 43  
 44  
 45  
 46  for(i=0;i<n;i++)
 47   S[i]=0;      //如果某點i被訪問則把該點值置為1,否則為0
 48   
 49   
 50   
 51  S[v1]=1;//已經被訪問置為1
 52  D[v1]=0;    //源點v送S
 53  
 54  
 55  
 56  for(i=0;i<n-1;i++)   //擴充紅點集
 57  {
 58   
 59   
 60     min=inf;//令inf>max,保證距離值為max的藍點能擴充到S中
 61     for(j=0;j<n;j++)//在當前藍點中選距離值最小的點k+1
 62     {
 63       if((!S[j])&&(D[j]<min))
 64       {
 65         min=D[j];//找從起點開始的最小權值
 66         k=j;
 67       }
 68     }
 69     
 70   
 71    S[k]=1;    //已經被訪問,置為1
 72   
 73   
 74   for(j=0;j<n;j++)
 75   {
 76     if((!S[j])&&(D[j]>D[k]+C[k][j]))//調整各藍點的距離值
 77     {
 78        D[j]=D[k]+C[k][j];  //修改藍點j+1的距離
 79        P[j]=k+1;     //k+1是j+1的前趨
 80     }
 81   }
 82   
 83   
 84  }  //所有頂點均已擴充到S中
 85  
 86  
 87  for(i=0;i<n;i++)//輸出結果和最短路徑
 88  {
 89   printf("%d到%d的最短距離為",v,i+1);
 90   printf("%d\n",D[i]);  //打印結果
 91   pre=P[i];
 92   printf("路徑:%d",i+1);
 93   while(pre!=0)  //繼續找前趨頂點
 94   {
 95    printf("<——%d",pre);
 96    pre=P[pre-1];
 97   }
 98   printf("\n");
 99  }
100  
101  
102 }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM