1、問題引入
在帶權有向圖中求解某個源點到其余各個頂點的最短路徑一般可以采用迪傑斯特拉算法(Dijkstra算法)。
2、算法的主體思想:
引用:(http://hi.baidu.com/wangziming/blog/item/d352be19d53e554642a9ad62.html)
A、找到v——Other所有路徑中的的最短路徑vd=v——d(Other的一個元素);
B、找到v——S——Other所有路徑中的的最短路徑vi=v——i(Other的一個元素);
C、比較vd和vi如果vd<=vi則將d加入S且從Other中刪除,否則將i加入S且從Other中刪除。
重復以上步驟直至Other為空集。
3、一個問題:
這里說明一個問題:假設S為已經求的的最短路徑的終點的集合,則可以證明:下一條最短路徑(設其終點為x)或者是弧(v,x),或者是中間只經過S中的頂點而最后到達頂點x的路徑;可以用反證法證明:(引用)我們求得的最短路徑是升序排列的,假設x是存在於v——Other(v1)——Other(v2)之中,那么肯定有一條比這條路徑更短的路徑v——Other(v1)我們沒找到,也就是說,我們所找的v2是從已經求的的最短路徑開始搜索的,,其前一個節點必然存在於S中,如果不存在於S中,這就算法本身的思路相背離,必然為不正確的。。。我剛開始看這個算法的時候也是糾結在這里,,一直看不明白,,覺得有些不理解,,以為v-other-other中說不定就存在比v-S-other或者v-other更短的路徑,,其實這是不可能的,,如果有最短的路徑,必然是已經求解出來的。。。。。
4、具體實現過程:
這個算法在許多書上都有介紹,嚴蔚敏老師的數據結構上就有,,,這里算法實現中和嚴老師的有一點點的區別,即:使用prev[i]來記錄從起始點到點i的最短路徑中i點的前一個節點,,這樣在最后得出路徑的時候直接從i向前直到起始點就可以方便得出了。。。
程序實現中用了一個txt文件,其中第一個值用於記錄點的個數,其他數據表示各個點之間的可達關系:比如
用txt文件表示為:
其中6表示有6個節點,,9999表示無窮大(本圖中最大的路徑長度不超過100),其他小於9999的表示實際路徑長度。。。。
(1)實現方法1:未采用最小優先級隊列

1 /*---------------------------------------------------------- 2 *name:迪傑斯特拉算法實現 3 *data:2012-5 4 *author:lp 5 *---------------------------------------------------------*/ 6 #include<stdio.h> 7 #include<stdlib.h> 8 #define max 9999 9 void Dijkstra(int ,int,int *,int *,int **); 10 void Search(int,int,int*); 11 void main() 12 { 13 int i,j,num,v,last;//num表示點的個數,v表示起始點; 14 FILE *p; 15 //2.txt中第一個數據表示點的個數,第二個數據表示起始點; 16 //其他數據為圖中點之間的可達關系,-1表示不可達 17 p=fopen("2.txt","r"); 18 if(!p) 19 { 20 printf("cannot open file 2.txt"); 21 exit(0); 22 } 23 fscanf(p,"%d",&num);//獲得點的個數 24 printf("請輸入起始點:"); 25 scanf("%d",&v); 26 int *d=(int*)malloc(sizeof(int)*num); 27 //prev[]用於記錄最短路徑中每個點的前一個點 28 int *prev=(int *)malloc(sizeof(int)*num); 29 //a[][]用於記錄各個點之間的路徑,-1表示不可直達,具體數據參見2.txt; 30 int **a=(int**)malloc(sizeof(int*)*num); 31 for(i=0;i<num;i++) 32 a[i]=(int*)malloc(sizeof(int)*num); 33 for(i=0;i<num;i++) 34 for(j=0;j<num;j++) 35 fscanf(p,"%d",&a[i][j]); 36 37 Dijkstra(v,num,prev,d,a); 38 printf("請輸入需要達到的終點(不大於%d): ",num-1); 39 scanf("%d",&last); 40 if(d[last]==max){} 41 else 42 printf("起始點%d到達終點%d的路徑長度為:%d\n",v,last,d[last]); 43 Search(v,last,prev); 44 45 } 46 void Dijkstra(int v,int num,int *prev,int *d,int **a) 47 { 48 //d[]用於記錄起始點到達終點的最短路徑 49 //s[]用於記錄節點是否已經加入到S(S:已經求的的最短路徑的終點的集合) 50 //prev[i]用於記錄從起始節點開始到達i節點的最短路徑中i節點的前一個節點 51 int i,j; 52 int *s=(int*)malloc(sizeof(int)*num);//s[i]=1表示i點已經為S中的點; 53 for(i=0;i<num;i++)//初始化的d[],s[],prev[]; 54 { 55 s[i]=0; 56 d[i]=a[v][i]; 57 if(d[i]<max) 58 prev[i]=v; 59 else prev[i]=-1; 60 } 61 d[v]=0; 62 s[v]=1; 63 for(i=1;i<num;i++) 64 { 65 int tmp=max; 66 int k=v; 67 for(j=0;j<num;j++)//得出一個V-S中的節點放入到S中。 68 if((!s[j])&& d[j]<tmp)//找到d[]最小的點。。。 69 { 70 k=j; 71 tmp=d[j]; 72 } 73 s[k]=1;//k節點放入S中 74 for(j=0;j<num;j++)//更新d[]和prev[] 75 { 76 if((!s[j])&& a[k][j]<max) 77 { 78 int newdist; 79 newdist=d[k]+a[k][j]; 80 if(newdist<d[j]) 81 { 82 d[j]=newdist; 83 prev[j]=k; 84 } 85 } 86 } 87 } 88 } 89 //Search函數主要利用prev[]得出節點v到節點last的最短路徑上的點, 90 //prev[]的值在Dijkstra函數中已經得到,,,, 91 void Search(int v,int last,int*prev) 92 { 93 if(prev[last]==-1) 94 { 95 printf("起始點%d不可達終點%d \n",v,last); 96 exit(0); 97 } 98 else 99 { 100 printf("起始點點%d到達終點%d的路徑為: ",v,last); 101 printf("%d <-- ",last); 102 int k=prev[last]; 103 while(k>v) 104 { 105 printf("%d <-- ",k); 106 k=prev[k]; 107 } 108 printf("%d\n",v); 109 } 110 }
(2)實現方法2:采用最小優先級隊列
(1)數據結構,嚴蔚敏。
(2):http://2728green-rock.blog.163.com/blog/static/43636790200901211848284/
(3):http://hi.baidu.com/wangziming/blog/item/d352be19d53e554642a9ad62.html
(4):http://blog.csdn.net/zrjdds/article/details/6728332