博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
理解Dijkstra算法
阅读量:6120 次
发布时间:2019-06-21

本文共 1776 字,大约阅读时间需要 5 分钟。

hot3.png

学习过最短路径问题的人都不会不知道Dijkstra算法。这个算法适用于解决无负权图的单源最短路径问题。这篇小文来谈谈如何理解这一算法。

这里首先给出一个Python 3的代码实现(以下代码出自,略有改动)。

from heapq import heappush, heappopdef dijkstra(G, s):    D, P, Q, C = {s: 0}, {s: None}, [(0, s, None)], set()    while Q:        du, u, p = heappop(Q)        if u in C: continue        C.add(u)        D[u], P[u] = du, p        for v in G[u]:            if v not in C:                heappush(Q, (du + G[u][v], v, u))    return D, P

Dijkstra算法可以从很多角度去理解。我个人觉得最便于理解和记忆的角度,是将其视为一个图遍历算法。这从上面的代码中就能够看出来。遍历节点的算法都需要记录“前线”,也就是所有已经访问过但没有“完全考察”的节点。不同的遍历算法,记录“前线”所用的数据结构也不同。比如,BFS使用的是FIFO的队列,DFS(暗中)使用的是FILO的栈,等等;而上面的代码使用的则是一个优先队列。(实际上,如果待解决的图的所有边的权重都为同一正值的话,那么该问题可以用BFS来解决。换言之,BFS算法可以视为Dijkstra算法的一个特例。)

那么,怎么直观地去理解Dijkstra算法所表示的这一遍历过程呢?比如说,我们要解决的问题如果可以表现为下面这幅图——这是幅无向无负权图,其中S点表示起点,每条边的权重就是标注在旁边的数字——那么怎么去表现Dijkstra算法所设定的遍历呢?

这里需要耍一个思维上的小花招:我们把每条边想象成真实的路径,然后把权重想象成对应路径的长度。然后假设站在起点S的是旋涡鸣人。在0时刻,旋涡鸣人首先将起点S涂成黑色(在代码中表现为加入C这个集合里),然后沿每条从S点出发的路径——在上图里就是SA、SB、SC三条边——派出一名影分身。这些影分身的速度都一样,每前进1个长度需花费1个时刻,所以在时刻7、9、14,这三个影分身分别依次到达C、B、A点。每个影分身到达自己的目的地时,都会检查该点有没有被涂黑;如果已经被涂黑,说明有别的影分身走了一条更短的路径来过这个点,那么这个后来的影分身就完成了自己的使命,可以“噗”地一下化成青烟消失了;如果没有被涂黑,那么说明这个影分身走的是起点S到该点的最短路径,记下现在的时刻(也就是所循路径的长度)以及上一个节点,把这一点涂黑,朝每条未被涂黑的邻点派出新的影分身,然后自己就可以消失掉了。例如上面的例子里,时刻9时,有一个从起点S出发的影分身会到达B点。由于B此时还是白色的,说明S到B的最短路径的长度为9。涂黑B点,然后朝A、E两点各派出一名影分身(之所以不往C点派影分身,是因为C点已经在时刻7被另一个从S点出发的影分身涂黑了,也就是已经在C这个集合里了)。注意从B点出发的影分身之一将在时刻11(=9+2)到达A点,早于从S点出发往A点去的那个影分身(他将在时刻14到达),所以等后者到达时,会发现A点已经是黑色的了。如此重复,直到所有的影分身都消失了,也即所有从S点能够到达的点都涂成了黑色(遍历),也记下了被涂黑的时刻(最短距离)和每一个中间节点(最短路径)。

按照这种理解,那么算法中的优先队列其实可以看作是时间轴。每次往优先队列里push一个元素,代表新派出一个影分身;而每次从优先队列里pop出一个元素,则代表了某个影分身到达了其目的节点。而且,这种思路还可以帮我们从直观上记忆Dijkstra算法的适用范围:必须无负权边,因为影分身所走路径的长度不可能为负;既可以是有向图也可以是无向图,影分身按照允许的方向走就行了。

以上就是我对Dijkstra算法的一点理解。希望能够对学习算法的同学有点帮助。

转载于:https://my.oschina.net/qiaotoubao/blog/735349

你可能感兴趣的文章
P127、面试题20:顺时针打印矩阵
查看>>
JS图片跟着鼠标跑效果
查看>>
[SCOI2005][BZOJ 1084]最大子矩阵
查看>>
学习笔记之Data Visualization
查看>>
Leetcode 3. Longest Substring Without Repeating Characters
查看>>
【FJOI2015】金币换位问题
查看>>
数学之美系列二十 -- 自然语言处理的教父 马库斯
查看>>
Android实现自定义位置无标题Dialog
查看>>
面试总结
查看>>
Chrome浏览器播放HTML5音频没声音的解决方案
查看>>
easyui datagrid 行编辑功能
查看>>
类,对象与实例变量
查看>>
HDU 2818 (矢量并查集)
查看>>
【转】php字符串加密解密
查看>>
22. linux 常用命令
查看>>
ASP.Net 使用GridView模板删除一行的用法
查看>>
(十六)字段表集合
查看>>
JPGraph
查看>>
实验二 Java面向对象程序设计
查看>>
------__________________________9余数定理-__________ 1163______________
查看>>