最短路径——迪杰斯特拉算法
2016-08-23 20:29
330 查看
前言
好久没有更新过算法的博客了,这篇博客主要介绍我们算法中很著名的一个问题——最短路径问题及解决最短路径问题的经典算法之一迪杰斯特拉算法。最短路径问题
最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。算法具体的形式包括:确定起点的最短路径问题 -即已知起始结点,求最短路径的问题。
确定终点的最短路径问题 -与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
确定起点终点的最短路径问题 -即已知起点和终点,求两结点之间的最短路径。
全局最短路径问题 -求图中所有的最短路径。
其实就是字面意思,一个带边值的图中从某一个顶点到另外一个顶点的最短路径。如下图所示:你能求出V0-V8的最短路径吗?
而解决最短路径问题最常见的算法就是迪杰斯特拉(Dijkstra)算法和弗洛伊德算法(Floyd)算法。
迪杰斯特拉(Dijkstra)算法
1.算法简介
Dijkstra算法是由E.W.Dijkstra于1959年提出,又叫迪杰斯特拉算法,它应用了贪心算法模式,是目前公认的最好的求解最短路径的方法。算法解决的是有向图中单个源点到其他顶点的最短路径问题,其主要特点是每次迭代时选择的下一个顶点是标记点之外距离源点最近的顶点。但由于dijkstra算法主要计算从源点到其他所有点的最短路径,所以算法的效率较低。2.算法原理
1.首先,引入一个辅助向量D,它的每个分量 D[i]
表示当前所找到的从起始点
v
(即源点
v
)到其它每个顶点
vi
的长度。
例如,D[3] = 2表示从起始点到顶点3的路径相对最小长度为2。这里强调相对就是说在算法执行过程中D的值是在不断逼近最终结果但在过程中不一定就等于长度。
2.D的初始状态为:若从v到vi 有弧(即从v到 vi 存在连接边),则D[i] 为弧上的权值(即为从 v 到vi 的边的权值);否则置D[i] 为∞。显然,长度为
D [j] = Min{ D | vj ∈V } 的路径就是从v 出发到顶点vj 的长度最短的一条路径,此路径为(v,vj )。
3.那么,下一条长度次短的是哪一条呢?也就是找到从源点v到下一个顶点的最短路径长度所对应的顶点,且这条最短路径长度仅次于从源点v 到顶点 vj 的最短路径长度。假设该次短路径的终点是vk,则可想而知,这条路径要么是( v,vk ),或者是(v,vj,vk )。它的长度或者是从v到vk 的弧上的权值,或者是D [j] 加上从vj 到vk 的弧上的权值。
4.一般情况下,假设S为已求得的从源点v出发的最短路径长度的顶点的集合,则可证明:下一条次最短路径(设其终点为x)要么是弧(v,x ),或者是从源点
![](https://oscdn.geek-share.com/Uploads/Images/Content/201608/6974ded72c840d4ac670f57ada8bc835.jpg)
出发的中间只经过S中的顶点而最后到达顶点
![](https://oscdn.geek-share.com/Uploads/Images/Content/201608/b16ba7064043a6234e2b47137ca3c82d.jpg)
的路径。因此,下一条长度次短的的最短路径长度必是D[j]=
Min{ D[i] |vi ∈V-S },其中D [i] 要么是弧( v,vi )上的权值,或者是D [k] ( vk ∈S)和弧( vk , vi )上的权值之和。
3、算法实例
我们看下面这幅图 求从 a 到 j 的最短路径。4、算法实现
#include<stdio.h> #include<stdlib.h> #define max 11000000000 inta[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 ); return0; }
5、性能分析
迪杰斯特拉算法的时间复杂度为O(n^2),空间复杂度为O(n^3)。正因为如此当图中点较多时,算法的效率会很低。于是就有了对迪杰斯特拉算法的优化,最常见的就是堆优化,后期将为大家介绍迪杰斯特拉算法的优化。相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法