一.理论基础
迪杰斯特拉算法(下文简称DJ算法)是理论基础是一条简单的定理:
下一条最短路径或者是弧(V0, Vx),或者是中间经过S中的某些顶点,而后到达Vx的路径。(S是最短路径已知的顶点集合)
(为了准确的描述定理,这里就直接摘抄了。。至于它对不对,嗯,据说反证法可证之)很明显这是一个递推算法:反复求下一条,直至没有下一条为止。
二.问题分析
现有加权有向图如下:
求从V0出发,到达其它各个顶点的最短路径。
首先为了把它转换成便于描述的数学形式,得写出对应的邻接矩阵(x表示不可达):
0 | 50 | 10 | x | 45 | x |
x | 0 | 15 | x | 10 | x |
20 | x | 0 | 15 | x | x |
x | 20 | x | 0 | 35 | x |
x | x | x | 30 | 0 | x |
x | x | x | 3 | x | 0 |
分析定理可以得出:目前S集合中只有1个顶点:V0(V0到自身的肯定是最短路径),除了S集合这个辅助空间外,我们还需要:
- V集合:最短路径未知的顶点组成的集合,即S集合的补集
- path[]:记录最短路径,用来显示结果
- dist[]:记录路径长度,作用同上
- Vx:记录下一个顶点
准备工作结束,可以开始求解了
三.求解过程
0.初始状态
dist[]初始化为V0到各个顶点的直接距离(x表示不可直达),path[]初始化为对应的路径,不可直达的记作NULL,选取V集合中dist值最小的顶点V2作为下一个顶点(定理中的Vx)
1.第1步
把V2加入S集合,我们多了一个中转站V2,接下来更新dist[],看借助V2中转的话是不是更短,根据计算结果更新dist[]和path[],把更短的路径长度和对应路径放进去,V集合中dist值最小的V3作为下一个顶点
2.第2-5步
继续选取下一个顶点,直至V集合中没有可选顶点为止
四.总结
DJ算法过程非常简单:
- 确定S中的第一个点(也就是源点V0);
- 根据定理递推(一直找最短,并试图借助最短中转)
算法思路本身不难,当初看不明白是因为被具体的伪代码实现绕进去了,所以学习算法应该关注思路而不是具体实现,尤其是伪代码算法,通常会随意声明一些奇怪的数据结构,却不解释为什么需要这些辅助空间,比如本例中,S集合和V集合只需要有一个即可,path[]和dist[]也可以用结构体清晰的表示出来,但伪代码中零零散散的全都用到了,过多的辅助空间反而妨碍了理解算法本身。