迪傑斯特拉(Dijkstra)演算法--無向網路最短路徑
阿新 • • 發佈:2018-12-20
與有向網路不同的是,無向網路的鄰接矩陣是對稱的,所以在構造鄰接矩陣的時候要注意。Dijkstra演算法的具體內容參照我上次寫的迪傑斯特拉(Dijstra)演算法——有向網路最短路徑
下面直接放程式碼和例項,以便更加理解使用。
#include<stdio.h> #define max 1000 //1000定義為最大值正無窮,表示兩點之間不直接相通,或與自己相連線。 #define n 100 //n表示一個範圍,需要大於圖的頂點數目,以便定義一個數組儲存。n的具體值根據情況而定。 main() { void DIJ(float C[n][n],int v); int i,j,k,e,r; float z; float a[n][n]; //定義一個足夠大的陣列,用於儲存圖的資料。 for(i=0;i<n;i++) for(j=0;j<n;j++) { a[i][j]=max; //在正式寫入資料之前,定義任意兩點之間是不連通的,以便在後面為連通的資料單獨賦值。 } printf("請輸入頂點數目和邊數:"); //明確圖中的節點數目和之間的邊數。 scanf("%d%d",&r,&e); printf("輸入各邊關係和權值:\n"); for(k=0;k<e;k++) //輸入各邊之間的連線點與權值。如1,2點之間的距離是10,應該輸入“1 2 10”。 { scanf("%d%d%f",&i,&j,&z); a[i-1][j-1]=z; //只建立有向圖用這句 a[j-1][i-1]=z; //建立無向圖時需要加上這行 } printf("\n構造鄰接矩陣:"); for(i=0;i<r;i++) //把圖用鄰接矩陣的形式輸出。 { printf("\n"); for(j=0;j<r;j++) { printf("%.1f\t",a[i][j]); } } printf("\n"); printf("請輸入起始點數字:"); //輸入需要從某個節點開始。 scanf("%d",&i); printf("\n距離\t路徑"); DIJ(a,i); } void DIJ(float C[n][n],int v) //Dijkstra演算法 { float D[n]; //用於儲存起始點到其他各點間的距離 int P[n],S[n]; //P[n]用陣列儲存當前點的前驅結點,S[n]表示已經取過的點集,代表紅點集。 int i,j,k,v1,pre; float min,inf=200; //inf一定要大於所有點間路徑最大的數,這樣才保證距離最大值的點能擴充到已經取好的點 v1=v-1; for(i=0;i<n;i++) { D[i]=C[v1][i]; //置初始距離值 if(D[i]!=max) //初始狀態下各前驅結點。 P[i]=v; else P[i]=0; //如果兩點非連線定義其前驅為0 } for(i=0;i<n;i++) S[i]=0; //紅點集開始是空集 S[v1]=1; //初始點入紅點集 D[v1]=0; //設定初始點到自身的距離為0 for(i=0;i<n-1;i++) //擴充紅點集 { min=inf; for(j=0;j<n;j++) if((!S[j])&&(D[j]<min)) { min=D[j]; k=j; } S[k]=1; //在當前藍點集中選取距離最小的頂點k+1,並加入紅點集 for(j=0;j<n;j++) if((!S[j])&&(D[j]>D[k]+C[k][j]))//調整各藍點的間距值 { D[j]=D[k]+C[k][j]; //修改藍點j+1到紅點集的距離 P[j]=k+1; //改變j+1的前驅為k+1 } } //所有頂點都擴充到S中 for(i=0;i<n;i++) { if(D[i]!=max) printf("\n%.1f\t%d",D[i],i+1); //列印兩點間能連通的結果 pre=P[i]; while(pre!=0) //用於繼續找前驅結點 { printf("<--%d",pre); pre=P[pre-1]; } } printf("\n"); }
有向網路和無向網路程式碼只有一行之差別,但是實際輸出結果卻大不相同。 下面以具體例項驗證。 有向網路圖 把上面的有向網路圖改成無向網路圖 鄰接矩陣也發生變化 以4為源點,輸出結果對比如下 有向網路輸出結果: 無向網路輸出結果: 由以上可以看出兩次輸出結果截然不同。
下面以另一個例子作為驗證。
下面是一個無向網路 鄰接矩陣在這裡就不再給出。 以4為源點,輸出結果如下 如果按照上圖輸入,就可以得到上圖結果。