首先我們需要熟悉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 }