【資料結構】單源最短路徑 Dijkstra演算法
阿新 • • 發佈:2018-11-30
單源最短路徑問題是指:對於給定的有向網路G=(V,E),求原點V0到其他頂點的最短路徑。
按照長度遞增的順序逐步產生最短路徑的方法,稱為Dijkstra演算法。
該演算法的基本思想:
把圖中的所有頂點分成兩組,第一組包括已確定最短路徑的頂點,初始時只含有一個源點,記為集合S;第二組包括尚未確定的最短路徑的頂點,記為V-S。按最短路徑長度遞增的順序逐個把V-S中的頂點加到S中去,直至從V0出發可以到達的所有頂點都包括到S中。在這個過程中,總保持V0到第一組S各頂點的最短路金都不大於從V0到第二組V-S的任何頂點的最短路徑,第二組的頂點對應的距離是從V0到此頂點的只包括第一組S的頂點為中間頂點的最短路徑長度。對於S中任意一點j,V0到j的路徑長度皆小於V0到V-S中任意一點的路徑的長度。
個人認為的關鍵步驟:
#include <stdio.h> #include <stdlib.h> const int FINITY = 5000; const int M = 20; int d[M];//最短路徑向量 int p[M];//路徑向量 typedef struct { char vexs[M];//頂點資訊域 int edges[M][M];//鄰接矩陣 int n,e; }Mgraph; void creat (Mgraph *g,int c) { int i,j,k,w; FILE *f; f=fopen("test.txt","r"); if(f) { fscanf(f,"%d%d",&g->n,&g->e); for(i=0;i<g->n;i++) fscanf(f,"%1s",&g->vexs[i]); for(i=0;i<g->n;i++)//初始化 { for(j=0;j<g->n;j++) { if(i==j) g->edges[i][j]=0; else g->edges[i][j]=FINITY; } } for(k=0;k<g->e;k++) { fscanf(f,"%d%d%d",&i,&j,&w); g->edges[i][j]=w; if(c==0) g->edges[j][i]=w; } fclose(f); } else { g->n=0; } } void print(Mgraph g) { int i,j; printf("%一共有%d個結點,%d條邊\n",g.n,g.e); for(i=0;i<g.n;i++) { for(j=0;j<g.n;j++) { printf("%-6d",g.edges[i][j]); } printf("\n"); } } void dijkstra (Mgraph g,int v0) { bool final[M]; int i,k,v,min; //第一步 初始化集合S與距離向量d for(v=0;v<g.n;v++) { final[v]=false; d[v]=g.edges[v0][v]; if(d[v]<FINITY && d[v]!=0) p[v]=v0; else p[v]=-1;//無前驅結點 } d[v0]=0; final[v0]=true; //第二步 依次找出n-1個結點加入S中 for(i=1;i<g.n;i++) { min=FINITY; for(k=0;k<g.n;k++) { if(!final[k] && d[k]<min)//!final[k] 表示k結點還在V-S中 { v=k; min=d[k]; } } printf("%c--%d\n",g.vexs[v],min); if(min==FINITY) return ; final[v]=true; for(k=0;k<g.n;k++) { if(!final[k] && (min+g.edges[v][k])<d[k]) { d[k]=min+g.edges[v][k]; p[k]=v; } } } } void print_gpd(Mgraph g,int v0)//輸出有向圖的最短路徑 { int st[M],i,pre,top=-1; for(i=0;i<g.n;i++) { printf("%c -> %c ",g.vexs[v0],g.vexs[i]); printf("Distance : %3d ,path:",d[i]); st[++top]=i; pre=p[i]; while(pre!=-1) { st[++top]=pre; pre=p[pre]; } while(top>0) { printf("%2d",st[top--]); } printf("\n"); } } int main () { int v0; Mgraph g; creat(&g,1); print(g); printf("請輸入V0:\n"); scanf("%d",&v0); dijkstra (g,v0); print_gpd(g,v0); return 0; }