-
迪杰斯特拉算法
编辑
迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。[1]
- 中文名
- 迪克斯特拉算法 外文名
- Dijkstra's Algorithm
- 分 类
- 计算机算法 用 途
- 单源最短路径问题
目录
Dijkstra算法是典型的算法。Dijkstra算法是很有代表性的算法。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。[2]
1.首先,引入一个辅助向量D,它的每个分量 D
表示当前所找到的 从起始点
(即源点
)到其它每个顶点
的长度。
例如,D[3] = 2表示从起始点到顶点3的路径相对最小长度为2。这里强调相对就是说在算法执行过程中D的值是在不断逼近最终结果但在过程中不一定就等于长度。[1]
2.D的初始状态为:若从
到
有弧(即从
到
存在连接边),则D
为弧上的权值(即为从
到
的边的权值);否则置D
为∞。
显然,长度为 D
= Min{ D |
∈V } 的路径就是从
出发到顶点
的长度最短的一条路径,此路径为(
)。
3.那么,下一条长度次短的是哪一条呢?也就是找到从源点
到下一个顶点的最短路径长度所对应的顶点,且这条最短路径长度仅次于从源点
到顶点
的最短路径长度。
假设该次短路径的终点是
,则可想而知,这条路径要么是(
),或者是(
)。它的长度或者是从
到
的弧上的权值,或者是D
加上从
到
的弧上的权值。
4.一般情况下,假设S为已求得的从源点
出发的最短路径长度的顶点的集合,则可证明:下一条次最短路径(设其终点为
)要么是弧(
),或者是从源点
出发的中间只经过S中的顶点而最后到达顶点
的路径。
因此,下一条长度次短的的最短路径长度必是D
= Min{ D
|
∈V-S },其中D
要么是弧(
)上的权值,或者是D
(
∈S)和弧(
,
)上的权值之和。
算法描述如下:
1)令arcs表示弧上的权值。若弧不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到的从
出发的的终点的集合,初始状态为空集。那么,从
出发到图上其余各顶点
可能达到的长度的初值为D=arcs[Locate Vex(G,
)],
∈V;
2)选择
,使得D
=Min{ D |
∈V-S } ;
3)修改从
出发的到集合V-S中任一顶点
的最短路径长度。[1]
在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短值。[2]
按路径长度递增次序产生算法:
把顶点集合V分成两组:
(1)S:已求出的顶点的集合(初始时只含有源点V0)
(2)V-S=T:尚未确定的顶点集合
将T中顶点按递增的次序加入到S中,保证:
(1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度
(2)每个顶点对应一个距离值
S中顶点:从V0到此顶点的长度
T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度
依据:可以证明V0到T中顶点Vk的,或是从V0到Vk的直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
(反证法可证)
求最短路径步骤
算法步骤如下:
G={V,E}
1. 初始时令 S={V0},T=V-S={其余顶点},T中顶点对应的距离值
若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
若不存在<V0,Vi>,d(V0,Vi)为∞
2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中
3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
pascal语言
下面是该算法的Pascal程序
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | typebool=array[1..10]ofboolean;arr=array[0..10]ofinteger;vara:array[1..10,1..10]ofinteger;//存储图的邻接数组,无边为10000c,d,e:arr;//c为最短路径数值,d为各点前趋,t:bool;//e:路径,t为辅助数组i,j,n,m:integer;inf,outf:text;procedureinit;//不同题目邻接数组建立方式不一样beginassign(inf,inputfile);assign(outf,outputfile);reset(inf);rewrite(outf);read(inf,n);fori:=1tondobeginforj:=1tondobeginread(inf,a[i,j]);ifa[i,j]=0thena[i,j]:=10000;end;end;end;proceduredijkstra(qi:integer;t:bool;varc{,d}:arr);//qi起点,{}中为求路径部分,不需求路径时可以不要vari,j,k,min:integer;begint[qi]:=true;//t数组一般在调用前初始,除起点外所有节点都化成false,也可将部分点初始化成true以回避这些点fori:=1tondod[i]:=qi;d[qi]:=0;fori:=1tondoc[i]:=a[qi,i];fori:=1ton-1dobeginmin:=maxint;//改为最大值forj:=1tondoif(c[j]<min)andnott[j]thenbegink:=j;min:=c[j];end;t[k]:=true;forj:=1tondoif(c[k]+a[k,j]<c[j])andnott[j]thenbeginc[j]:=c[k]+a[k,j];d[j]:=k;end;end;end;proceduremake(zh:integer;d:arr;vare:arr);//生成路径,e[0]保存路径vari,j,k:integer;//上的节点个数begini:=0;whiled[zh]<>0dobegininc(i);e[i]:=zh;zh:=d[zh];end;inc(i);e[i]:=qi;e[0]:=i;end; |
主程序调用:求长度:初始化t,然后dijkstra(qi,t,c,d)
求路径:make(m,d,e) ,m是终点
java语言
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | //初始化路径,都为最大值。intpath[][]=newint[n+1][n+1];for(inti=1;i<n+1;i++){for(intj=1;j<n+1;j++)path[i][j]=Integer.MAX_VALUE;}//这里需要输入path[i][j]的具体内容,如果有重复数据的话,需要更新路径为最小值。intminLen[]=newint[n+1];//visit初始为0,防止回溯intvisit[]=newint[n+1];//初始化1到其他点的距离。for(inti=1;i<n+1;i++){minLen[i]=path[1][i];}voidDijkstra(){minLen[1]=0;visit[1]=1;intminj=1;for(inti=1;i<n+1;i++){intmin=Integer.MAX_VALUE;for(intj=1;j<n+1;j++){if(visit[j]==0&&minLen[j]<min){min=minLen[j];minj=j;}}visit[minj]=1;for(intj=1;j<n+1;j++){if(visit[j]==0&&minLen[minj]!=Integer.MAX_VALUE&&path[minj][j]!=Integer.MAX_VALUE&&minLen[j]>(minLen[minj]+path[minj][j])){minLen[j]=minLen[minj]+path[minj][j];}}}} |
C语言
下面是该算法的C语言实现[1]
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include<stdio.h>#include<stdlib.h>#define max 11000000000inta[1000][1000];intd[1000];//d表示某特定边距离intp[1000];//p表示永久边距离inti,j,k;intm;//m代表边数intn;//n代表点数intmain(){scanf("%d%d",&n,&m);intmin1;intx,y,z;for(i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);a[x][y]=z;a[y][x]=z;}for(i=1;i<=n;i++)d[i]=max1;d[1]=0;for(i=1;i<=n;i++){min1=max1;for(j=1;j<=n;j++)if(!p[j]&&d[j]<min1){min1=d[j];k=j;}p[k]=j;for(j=1;j<=n;j++)if(a[k][j]!=0&&!p[j]&&d[j]>d[k]+a[k][j])d[j]=d[k]+a[k][j];}for(i=1;i<n;i++)printf("%d->",p[i]);printf("%d\n",p[n]);return0;} |
大学经典教材<<数据结构>>(C语言版 严蔚敏 吴为民 编著) 中该算法的实现
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | /*测试数据 教科书 P189 G6 的邻接矩阵 其中 数字 1000000 代表无穷大61000000 1000000 10 100000 30 1001000000 1000000 5 1000000 1000000 10000001000000 1000000 1000000 50 1000000 10000001000000 1000000 1000000 1000000 1000000 101000000 1000000 1000000 20 1000000 601000000 1000000 1000000 1000000 1000000 1000000结果:D[0] D[1] D[2] D[3] D[4] D[5] 0 1000000 10 50 30 60*/#include <iostream>#include <cstdio>#define MAX 1000000using namespace std;int arcs[10][10];//邻接矩阵int D[10];//保存最短路径长度int p[10][10];//路径int final[10];//若final[i] = 1则说明 顶点vi已在集合S中int n = 0;//顶点个数int v0 = 0;//源点int v,w;void ShortestPath_DIJ(){ for (v = 0; v < n; v++) //循环 初始化 { final[v] = 0; D[v] = arcs[v0][v]; for (w = 0; w < n; w++) p[v][w] = 0;//设空路径 if (D[v] < MAX) {p[v][v0] = 1; p[v][v] = 1;} } D[v0] = 0; final[v0]=0; //初始化 v0顶点属于集合S //开始主循环 每次求得v0到某个顶点v的最短路径 并加v到集合S中 for (int i = 1; i < n; i++) { int min = MAX; for (w = 0; w < n; w++) { //我认为的核心过程--选点 if (!final[w]) //如果w顶点在V-S中 { //这个过程最终选出的点 应该是选出当前V-S中与S有关联边 //且权值最小的顶点 书上描述为 当前离V0最近的点 if (D[w] < min) {v = w; min = D[w];} } } final[v] = 1; //选出该点后加入到合集S中 for (w = 0; w < n; w++)//更新当前最短路径和距离 { /*在此循环中 v为当前刚选入集合S中的点 则以点V为中间点 考察 d0v+dvw 是否小于 D[w] 如果小于 则更新 比如加进点 3 则若要考察 D[5] 是否要更新 就 判断 d(v0-v3) + d(v3-v5) 的和是否小于D[5] */ if (!final[w] && (min+arcs[v][w]<D[w])) { D[w] = min + arcs[v][w]; // p[w] = p[v]; p[w][w] = 1; //p[w] = p[v] + [w] } } }}int main(){ cin >> n; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> arcs[i][j]; } } ShortestPath_DIJ(); for (int i = 0; i < n; i++) printf("D[%d] = %d\n",i,D[i]); return 0;} |
思考
该算法复杂度为n^2,我们可以发现,如果边数远小于n^2,对此可以考虑用堆这种数据结构进行优化,取出最短路径的复杂度降为O(1);每次调整的复杂度降为O(elogn);e为该点的边数,所以复杂度降为O((m+n)logn)。
实现
1. 将与源点相连的点加入堆,并调整堆。
2. 选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。
3. 处理与u相邻的,未被访问过的,满足三角不等式的顶点
1):若该点在堆里,更新距离,并调整该元素在堆中的位置。
2):若该点不在堆里,加入堆,更新堆。
4. 若取到的u为终点,结束算法;否则重复步骤2、3。
代码
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | procedureDijkstra;varu,v,e,i:longint;beginfillchar(dis,sizeof(dis),$7e);//距离fillchar(Inh,sizeof(Inh),false);//是否在堆中fillchar(visit,sizeof(visit),false);//是否访问过size:=0;e:=last[s];whilee<>0do//步骤1beginu:=other[e];ifnot(Inh[u])then//不在堆里begininc(size);heap[size]:=u;dis[u]:=cost[e];Loc[u]:=size;//Loc数组记录元素在堆中的位置Inh[u]:=true;Shift_up(Loc[u]);//上浮endelseifcost[e]<dis[u]then//在堆里begindis[u]:=cost[e];Shift_up(Loc[u]);Shift_down(Loc[u]);end;e:=pre[e];end;visit[s]:=true;whiletruedobeginu:=heap[1];//步骤2ifu=tthenbreak;//步骤4visit[u]:=true;heap[1]:=heap[size];dec(size);Shift_down(1);e:=last[u];whilee<>0do//步骤3beginv:=other[e];ifNot(visit[v])and(dis[u]+cost[e]<dis[v])then//与u相邻的,未被访问过的,满足三角不等式的顶点ifInh[v]then//在堆中begindis[v]:=dis[u]+cost[e];Shift_up(Loc[v]);Shift_Down(Loc[v]);endelse//不再堆中begininc(size);heap[size]:=v;dis[v]:=dis[u]+cost[e];Loc[v]:=size;Inh[v]:=true;Shift_up(Loc[v]);end;e:=pre[e];end;end;writeln(dis[t]);end; |
- 参考资料
词条标签:
迪杰斯特拉算法图册
V百科往期回顾
- 词条统计
-
- 浏览次数:343708次
- 编辑次数:76次历史版本
- 最近更新:2016-05-29
- 创建者:317611123
src="http://entry.baidu.com/rp/home?type=pageembed&di=u2140330&rsi0=270&rsi1=175&title=%E8%BF%AA%E6%9D%B0%E6%96%AF%E7%89%B9%E6%8B%89%E7%AE%97%E6%B3%95_%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91<u=http%3A%2F%2Fbaike.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO&ref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO%26wd%3D%26eqid%3Dd61a7a7d000011640000000457ebb3a9&pageWidth=1169&pageHeight=827&t=1475064805210&iframeWidth=1169&iframeHeight=827" align="center,center" marginwidth="0" marginheight="0" class="BAIDU_SS_HHIFRAME" scrolling="no" frameborder="0" allowtransparency="true" style="display: block; width: 270px; height: 175px; background-color: transparent;">
id="iframeu1997633_0" src="http://pos.baidu.com/xcgm?rdid=1997633&dc=2&di=u1997633&dri=0&dis=0&dai=1&ps=0x0&coa=wn%3D2%26hn%3D8&dcb=BAIDU_SSP_define&dtm=HTML_POST&dvi=0.0&dci=-1&dpt=none&tsr=0&tpr=1475064805031&ti=%E8%BF%AA%E6%9D%B0%E6%96%AF%E7%89%B9%E6%8B%89%E7%AE%97%E6%B3%95_%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91&ari=2&dbv=2&drs=3&pcs=1169x827&pss=1169x9068&cfv=18&cpl=6&chi=1&cce=true&cec=UTF-8&tlm=1475064805&rw=827<u=http%3A%2F%2Fbaike.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO<r=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO%26wd%3D%26eqid%3Dd61a7a7d000011640000000457ebb3a9&ecd=1&psr=1440x900&par=1375x876&pis=-1x-1&ccd=24&cja=true&cmi=8&col=zh-CN&cdo=-1&tcn=1475064805&qn=dd41c9ba3c55a69e&tt=1475064804993.43.440.445" width="250" height="250" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="display: block; border-width: 0px; border-style: initial; vertical-align: bottom; margin: 0px;">
猜你喜欢
id="iframe1120393_0" src="http://pos.baidu.com/xcgm?mpdi=203980&rtbid=1969725&rdid=9223372032564609772&dc=2&di=1120393&dri=0&dis=0&dai=2&ps=8799x104&dcb=BAIDU_SSP_define&dtm=HTML_POST&dvi=0.0&dci=-1&dpt=none&tsr=0&tpr=1475064805031&ti=%E8%BF%AA%E6%9D%B0%E6%96%AF%E7%89%B9%E6%8B%89%E7%AE%97%E6%B3%95_%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91&ari=2&dbv=2&drs=3&pcs=1169x827&pss=1169x9068&cfv=18&cpl=6&chi=1&cce=true&cec=UTF-8&tlm=1475064805&rw=827<u=http%3A%2F%2Fbaike.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO<r=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DNr56Guiec9n-ZTMXxA9SUVGiKQOhTMRdNM16VkCjEGvhj17gHdpOl4eP1Kf6vWVfq6xUC_7rYrMqNN7gpUnT5ZNA8LJiM7gkMLVBzt7GW9rsdzVulvyazVfX22LmcKwwKjio4YPTUtf0T0nDbWp2Z7pf3EitqAWEWWwpfkBUjdO%26wd%3D%26eqid%3Dd61a7a7d000011640000000457ebb3a9&ecd=1&psr=1440x900&par=1375x876&pis=-1x-1&ccd=24&cja=true&cmi=8&col=zh-CN&cdo=-1&tcn=1475064805&qn=4fe6bf408add6e71&dpv=4fe6bf408add6e71&tt=1475064804993.103.452.453" width="960" height="90" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="display: block; border-width: 0px; border-style: initial; vertical-align: bottom; margin: 0px;">














