Dijkstra算法:
首先。引进一个辅助向量D。它的每一个分量D[i]表示当前所找到的从始点v到每一个终点vi的的长度:如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近终于结果但在过程中不一定就等于长度。
它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条。此路径为(v,vj)。 那么,下一条长度次短的是哪一条呢?如果该次短路径的终点是vk。则可想而知。这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。
普通情况下,如果S为已求得的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间仅仅经过S中的顶点而最后到达顶点X的路径。
因此,下一条长度次短的的长度必是D[j]=Min{D | vi∈V-S} 当中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。
算法描写叙述例如以下:
1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的度的初值为D=arcs[Locate Vex(G,v),i] vi∈V
2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)改动从v出发到集合V-S上任一顶点vk可达的最短路径长度。
考虑例如以下无向网(如果从v0出发):
最短路径数组变化情况:
最初。v0能到达的点为v2,v4,v5,距离分别为10,30,100,到其余点的距离默觉得无穷大(max),
然后。取最小权10,纳入S集。即v2点。又v2能够到达v3。距离为50。则v0->v3的距离可为10+50=60,小于当前的值(max),故更新辅助数组。紧接着,再取出一个最小权30(去掉之前的10),即v4,又v4能够到达v3,v5,距离分别为20,60,则v0->v3,v0->v5的距离能够分别为30+20=50,30+60=90,小于眼下的值60,100,故而继续更新辅助数组。以此类推。终于得到一个最短路径数组。
实现:
/************************************** 迪杰斯特拉算法求最短路径 by Rowandjj 2014/7/10 **************************************/ #include<iostream> using namespace std; #define INFINTY 65535 #define MAX_INFO 20 #define MAX_VERTEX_NUM 20 typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef int ShortPathTable[MAX_VERTEX_NUM]; typedef struct _ARC_ { int adj;//顶点关系类型 char *info; }AdiMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct _GRAPH_//图的邻接矩阵存储形式 { char vexs[MAX_VERTEX_NUM]; AdiMatrix arcs; int arcnum,vexnum; }Graph; //----------------------- int LocateVex(Graph G,char u); void CreateDN(Graph *G); void Display(Graph G); void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D); //--------------------------------------------- int main() { Graph g; CreateDN(&g); Display(g); PathMatrix p; ShortPathTable d; ShortestPath_DIJ(g,0,&p,&d); int i,j; printf("最短路径数组p[i][j]例如以下:\n"); for(i=0;i<g.vexnum;++i) { for(j=0;j<g.vexnum;++j) cout<<p[i][j]<<"\t"; cout<<endl; } cout<<"到各顶点的最短路径长度为:"<<endl; for(i=1;i<g.vexnum;++i) cout<<g.vexs[0]<<"-->"<<g.vexs[i]<<":"<<d[i]<<endl; return 0; } //-------------------------------------------- int LocateVex(Graph G,char u) { int i = 0; for(i = 0; i < G.vexnum;i++) { if(u == G.vexs[i]) { return i; } } return -1; } void CreateDN(Graph *G)//构建有向网 { int incInfo; int i,j,k,l,w; char s[MAX_INFO]; cout<<"请输入有向网G的顶点数,弧数,弧是否含其他信息(是:1,否:0)"<<endl; cin>>G->vexnum; cin>>G->arcnum; cin>>incInfo; char va,vb;//分别代表弧头、弧尾 char *pInfo; cout<<"请输入顶点值"<<endl; for(i = 0; i < G->vexnum; i++) { cin>>G->vexs[i]; } for(i = 0; i < G->vexnum; i++) { for(j = 0; j < G->vexnum; j++) { G->arcs[i][j].adj = INFINTY;//网 G->arcs[i][j].info = NULL; } } cout<<"请输入弧尾、弧头、权值"<<endl; for(k = 0; k < G->arcnum; k++) { cin>>va; cin>>vb; cin>>w; i = LocateVex(*G,va); j = LocateVex(*G,vb); G->arcs[i][j].adj = w; if(incInfo) { cout<<"请输入该弧的信息"<<endl; cin>>s; l = strlen(s); if(l) { pInfo = (char *)malloc(sizeof(char)*(l+1)); strcpy(pInfo,s); G->arcs[i][j].info = pInfo; } } } } void Display(Graph G) { int i,j; for(i = 0; i < G.vexnum; i++) { for(j = 0; j < G.vexnum; j++) { cout<<G.arcs[i][j].adj<<"\t"; } cout<<endl; } cout<<endl; } void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D) { int v,w,i,j,min; int final[MAX_VERTEX_NUM]; for(v=0;v<G.vexnum;++v) { final[v]=0; (*D)[v]=G.arcs[v0][v].adj; for(w=0;w<G.vexnum;++w) (*P)[v][w]=0; /* 设空路径 */ if((*D)[v]<INFINTY) { (*P)[v][v0]=1; (*P)[v][v]=1; } } (*D)[v0]=0; final[v0]=1; /* 初始化,v0顶点属于S集 */ for(i=1;i<G.vexnum;++i) /* 其余G.vexnum-1个顶点 */ { /* 開始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */ min=INFINTY; /* 当前所知离v0顶点的近期距离 */ for(w=0;w<G.vexnum;++w) { if(!final[w]) /* w顶点在V-S中 */ { if((*D)[w]<min) { v=w; min=(*D)[w]; } /* w顶点离v0顶点更近 */ } } final[v]=1; /* 离v0顶点近期的v增加S集 */ for(w=0;w<G.vexnum;++w) /* 更新当前最短路径及距离 */ { if(!final[w]&&min<INFINTY&&G.arcs[v][w].adj<INFINTY&&(min+G.arcs[v][w].adj<(*D)[w])) { /* 改动D[w]和P[w],w∈V-S */ (*D)[w]=min+G.arcs[v][w].adj; for(j=0;j<G.vexnum;++j) (*P)[w][j]=(*P)[v][j]; (*P)[w][w]=1; } } } }
測试: