图的最短路径算法-Dijkstra算法
什么是Dijkstra算法
Dijkstra 的全名叫 Edsger Wybe Dijkstra(艾兹赫尔·韦伯·戴克斯特拉),Dijkstra算法便是由Dijkstra本人发明的求图最短路径的算法,中文名为[迪杰斯特拉]算法。
Dijkstra 算法是一种计算从单个源到所有其他源的最短路径的贪心算法。
Dijkstra算法使用了广度优先搜索解决带权有向图的单源最短路径问题。通过一个顶点作为源节点然后找到该顶点到图中所有其它节点的最短路径,产生一个最短路径树。
Dijkstra算法至今仍用在诸多地方,如水浒Q传这类回合制游戏的自动寻路、在百度地图上寻找去某间好吃的餐馆的最短路线,都离不开最短路径算法。
Dijkstra算法详细步骤
以下算法详细步骤图,均来自公众号”程序员小灰”的文章——《漫画:图的”最短路径”问题》
假设有这样一个有向图,我们求从顶点A到其他顶点的最短路径距离是多少。
此时,我们需要构建一个距离表和访问记录表。
距离表的key值对应实例图的顶点,对应的value是从起点A到对应顶点的已知距离。在默认情况下,从起点A到其他顶点的距离都是无穷大。
访问记录表记录着图实例各个顶点的访问情况,默认均为false(即未访问)。
通过顶点A,知道顶点A的相邻顶点有B和C,顶点A到顶点B的距离是5,顶点A到顶点C的距离是2。因为目前距离表中的顶点B和顶点C都是默认的无穷大,此时便可把目前所知的距离(A到B是5,A到C是2),更新到距离表中,同时将顶点A在访问记录表中记录为已访问。
此时,距离表中,路径最短的顶点是顶点C,则我们从顶点C开始探索,可知顶点C的相邻顶点有D和F(顶点A在访问记录表中为已访问,不需要考虑)。
顶点C到顶点D的距离是6,所以顶点A到顶点D的距离是2+6=8。
顶点C到顶点F的距离是8,所以顶点A到顶点F的距离为2+8=10。
顶点D和顶点F在距离表中均为默认的无穷大,此时便可把上述所得到的距离更新到距离表中,同时将顶点C在访问记录表中记录为已访问。
此时,距离表中,路径最短的顶点是顶点B(顶点A和顶点C在访问记录表中为已访问,不需要考虑),则我们从顶点B开始探索,可知顶点B的相邻顶点有D和E(顶点A在访问记录表中为已访问,不需要考虑)。
顶点B到顶点D的距离是1,所以顶点A到顶点D的距离是5+1=6。
顶点B到顶点E的距离是6,所以顶点A到顶点E的距离为2+8=11。
顶点A到顶点D的距离6,小于当前距离表中的8,此时我们需覆盖掉原来距离表中顶点D的8,刷新为新值6。
顶点A到顶点E的距离11,顶点F在距离表为默认的无穷大,可以刷新无穷大为已知新距离值11。
同时将顶点B在访问记录表中记录为已访问。
剩下的步骤也如同上部分一样,通过距离表逐个判断图实例顶点的最短路径,迭代刷新,用新路径长度刷掉旧的路径长度,最终得到从起点到任意其他顶点的最短距离:
此时,距离表中,路径最短的顶点是顶点D(顶点A、顶点B和顶点C在访问记录表中为已访问,不需要考虑),则我们从顶点D开始探索,可知顶点D的相邻顶点有E和F(顶点B和顶点C在访问记录表中为已访问,不需要考虑)。
顶点D到顶点E的距离是1,所以顶点A到顶点E的距离是6+1=7。
顶点D到顶点F的距离是2,所以顶点A到顶点F的距离为6+2=8。
顶点A到顶点E的距离7,小于当前距离表中的11,顶点A到顶点F的距离8,小于当前距离表中的10。
我们此时便可以把距离表中的顶点E距离覆盖为7,顶点F在的距离覆盖为8。
同时将顶点D在访问记录表中记录为已访问。
此时,距离表中,路径最短的顶点是顶点E(顶点A、顶点B、顶点C和顶点D在访问记录表中为已访问,不需要考虑),则我们从顶点E开始探索,可知顶点E的相邻顶点有G(顶点B和顶点D在访问记录表中为已访问,不需要考虑)。
顶点E到顶点G的距离是7,所以顶点A到顶点G的距离是7+7=14。
顶点G在距离表中仍然是默认的无穷大,我们此时便可以把距离表中的顶点G距离覆盖为14。
同时将顶点E在访问记录表中记录为已访问。
此时,距离表中,路径最短的顶点是顶点F(顶点A、顶点B、顶点C、顶点D和顶点E在访问记录表中为已访问,不需要考虑),则我们从顶点F开始探索,可知顶点E的相邻顶点有G(顶点C和顶点D在访问记录表中为已访问,不需要考虑)。
顶点F到顶点G的距离是3,所以顶点A到顶点G的距离是8+3=11(路径A-B-D-F-G)。
我们此时便可以把距离表中的顶点G距离覆盖为11。
同时将顶点G在访问记录表中记录为已访问,到此位置,图实例的全部顶点均遍历完毕。
此时将距离表返回,距离表中此时存储的数值,便是顶点A到其他顶点的最短距离。
代码实现
1 |
|
代码用例
如果有这样一个邻接矩阵图实例
1 |
|
使用Dijkstra算法后得到的结果如下:
1 |
|