摘要

理解 Dijkstra 算法,可以想象将石头依次从桌子上提起来的场景,绷直的边就是最短的路径。比较难理解就是松弛操作,需要多思考一些。看来算法也是源于自然和生活啊(没有根据的猜测)!!!

Dijkstra 是单源最短路径算法,可以用于计算一个顶点到其他所有顶点的最短路径,它有一个局限性,就是不能有负权边。其时间复杂度可以优化到 O(ElogV),E 是边的数量,V 是顶点的数量。

Dijkstra 算法是由荷兰科学家 Edsger Wybe Dijkstra 发明,曾在1972年获得图灵奖。

在学习 Dijkstra 算法之前,先想象一下这样一个场景,将顶点想象成石头,边想象成连接石头之间的绳子,边的权值对应到绳子的长度,权值越大,绳子越长。

现在将这些用绳子连接的石头放在桌子上,选择其中一个石头,逐渐向上提起来,直到让所有石头都离开桌子。最后绷直的绳子就是这个石头到其他石头的最短路径。

这里有一个特别留意的点,就是后离开的石头都是被先离开的石头拉起来的。如下图所示(红色的线表示没有绷直的线):

左侧图中,拿石头 A 往上提,一次离开桌子的是,E、C、D、B(E 和 C 是同时起来),所以最短路径上,比如顶点 A 到顶点 B 的路径是 A -> E(或者C) -> D -> B,而不是顶点 A 直接到 B。

Dijkstra 算法就和提石头的操作非常一致。在代码实现上,需要添加松弛操作,松弛操作就是更新两个顶点之间的最短路径。通过松弛操作,尝试找出最终的最短路径。

先上代码,通过代码重新来梳理一下 Dijkstra 算法:

Map<V, PathInfo<V, E>> dijkstra(V begin) {Vertex<V, E> beginVertex = vertices.get(begin);if (beginVertex == null) return null;Map<V, PathInfo<V, E>> selectedPaths = new HashMap<>();Map<Vertex<V, E>, PathInfo<V, E>> paths = new HashMap<>();// 把起点也当作松弛操作的点处理paths.put(beginVertex, new PathInfo<>(weightManager.zero()));while (!paths.isEmpty()) {Map.Entry<Vertex<V, E>, PathInfo<V, E>> minEntry = getMinPath(paths);// minEntry 离开桌面Vertex<V, E> minVertex = minEntry.getKey();PathInfo<V, E> minPath = minEntry.getValue();selectedPaths.put(minEntry.getKey().value, minPath);paths.remove(minVertex);// 对它的 minVertex 的 outEdges 进行松弛操作for (Edge<V, E> edge : minVertex.outEdges) {// 如果 edge.to 已经离开桌面,就没有必要进行松弛操作 if (selectedPaths.containsKey(edge.to.value)) continue;relaxForDijkstra(edge, minPath, paths);}}selectedPaths.remove(begin);return selectedPaths;
}

函数中的前两行代码是获取 begin 的顶点,作为开始顶点,并保证 begin 顶点不是 null。

接下来创建两个 HashMap 类型的容器(可以认为是容器),先将 begin 顶点放在 paths 中。到这里会看到 weightManager 对象,它是处理边权值操作,这里的 zero() 表示权值为 0。

遍历 paths 集合,逐个从中找出最小的路径出来,实现的函数是 getMinPath 函数,具体实现如下所示:

Map.Entry<Vertex<V, E>, PathInfo<V, E>> getMinPath(Map<Vertex<V, E>, PathInfo<V, E>> paths) {Iterator<Map.Entry<Vertex<V, E>, PathInfo<V, E>>> it = paths.entrySet().iterator();Map.Entry<Vertex<V, E>, PathInfo<V, E>> minEntry = it.next();while (it.hasNext()) {Map.Entry<Vertex<V, E>, PathInfo<V, E>> entry = it.next();if (weightManager.compare(entry.getValue().weight, minEntry.getValue().weight) < 0) {minEntry = entry;}}return minEntry;
}

代码中实现的逻辑大致是这样,首先使用迭代器拿出 paths 中的元素,然后遍历元素,找出其中权值最小的元素返回。这里的 weightManager.compare() 函数就是比较两个权值的大小。

当拿出最小路径的元素之后,就将其赋值到 selectedPaths 集合中,并将该元素从 paths 集合中移除。此时也要记录最小权值时的顶点和最小权值的边。

再接下来,就是遍历这个顶点的边,如果边的另外一个顶点已经在 selectedPaths 集合中,就不做处理,然后做松弛操作。

松弛操作定义的函数是 relaxForDijkstra,还是先上代码:

private void relaxForDijkstra(Edge<V, E> edge, PathInfo<V, E> fromPath, Map<Vertex<V, E>, PathInfo<V, E>> paths) {// 新的可选择最短路径:beginVertex 到 dege.from 的最短路径 + edge.weightE newWeight = weightManager.add(fromPath.weight, edge.weight);// 以前的最短路径: beginVertex 到 edge.to 的最短路径PathInfo<V, E> oldPath = paths.get(edge.to);if (oldPath != null && weightManager.compare(newWeight, oldPath.weight) >= 0) return;if (oldPath == null) {oldPath = new PathInfo<>();paths.put(edge.to, oldPath);} else {oldPath.edgeInfos.clear();}oldPath.weight = newWeight;oldPath.edgeInfos.addAll(fromPath.edgeInfos);oldPath.edgeInfos.add(edge.info());
}

relaxForDijkstra 函数中要传入的参数分别是:

  • edge:需要进行松弛的边

  • fromPath:edge 的 from 的最短路径信息

  • paths:存放着其他顶点(没有提起来)的最短路径信息

首先将已经确定的最短路径权值加上要松弛边的权值,作为新的权值。然后从 paths 集合中拿到边的另外一个顶点信息,比较这两者的权值大小,如果新的权值比另外一个顶点信息的权值小时,就将另外一个顶点信息更改为新权值的信息。即可以看到 oldPath 移除 edgeInfos ,然后添加新的权值,边信息等(最后三行代码)。

这个需要想象一下从桌子上提起石头的案例,来理解松弛操作。就是比如你已经有开始顶点到另外一个顶点的边(或者路径),之后发现了一个新的到这个顶点的边(或者逻辑),你就比较这个边(或者路径)的权值,留下权值最小的,即替换处理。

当遍历循环和松弛操作处理完之后,就可以做最后一步了,就是移除开始的顶点,然后返回 selectedPaths 集合。

总结

  • Dijkstra 算法可以想象为将石头依次从桌子上提起来,绷直的边就是最短路径了;

  • 代码实现上要理解松弛操作,就是出现顶点到另外一个边的路径(大于两条),就比较,保留权值最小的边,路径;

  • 理解代码时,要时刻想象将石头依次从桌子上提起来的场景。

数据结构与算法-进阶(十二)最短路径Dijkstra 算法相关推荐

  1. python棋盘最短路径_Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例...

    本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个 ...

  2. JAVA编程求单源最短路径_【算法】单源最短路径——dijkstra算法

    一,概念 单源最短路径 给定一个带权有向图G=(V,E),其中每条边的权是一个实数.另外,还给定V中的一个顶点,称为源.要计算从源到其他所有各顶点的最短路径长度.这里的长度就是指路上各边权之和.这个问 ...

  3. 知识点二十四:最短路径——Dijkstra 算法

    前言 像 Google 地图.百度地图.高德地图这样的地图软件,你只需要输入起始.结束地址,地图就会给你规划一条最优出行路线.这里说的最优路线,有很多种定义,比如最短路线.最少用时路线.最少红绿灯路线 ...

  4. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  5. 12_JavaScript数据结构与算法(十二)二叉树

    JavaScript 数据结构与算法(十二)二叉树 二叉树 二叉树的概念 如果树中的每一个节点最多只能由两个子节点,这样的树就称为二叉树: 二叉树的组成 二叉树可以为空,也就是没有节点: 若二叉树不为 ...

  6. 最短路径-Dijkstra算法与Floyd算法

    最短路径-Dijkstra算法与Floyd算法 原文:https://www.cnblogs.com/smile233/p/8303673.html 一.最短路径 ①在非网图中,最短路径是指两顶点之间 ...

  7. 经典算法研究系列:二、Dijkstra 算法初探

    经典算法研究系列:二.Dijkstra 算法初探  July   二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...

  8. 分支限界法:单源最短路径--dijkstra算法

    单源最短路径–dijkstra算法 前面已经多次介绍过dijkstra算法是贪心算法,是动态规划,实际上可以从分支限界的角度来理解: 分支限界法 分支限界法,实际上就是回溯法,一般意义的回溯法是基于深 ...

  9. 遍历所有点的最短路径python_图遍历算法之最短路径Dijkstra算法

    一.最短路径问题(shortest path problem) 最短路径问题是图论研究中一个经典算法问题,旨在寻找图中两节点或单个节点到其他节点之间的最短路径.根据问题的不同,算法的具体形式包括: 确 ...

  10. 最短路径——Dijkstra算法与Floyd算法

    最短路径 Dijkstra算法 C语言代码实现 代码解析 Floyd算法 算法解析 C语言代码实现 最短路径问题 最短路径问题是我们经常会面临的一种决策问题.在图论中,非网图(边没有权值)的最短路径就 ...

最新文章

  1. flask项目中无法更改端口号
  2. Java中有几种类型的流?以及常见的实现类都有哪些?
  3. Kinect 动作识别组件概要设计
  4. 阿里 双11 同款流控降级组件 Sentinel Go 正式 GA,助力云原生服务稳稳稳
  5. Compass 更智能的搜索引擎(3)--高亮,排序,过滤以及各种搜索
  6. java 只显示文本文件_Java设计并实现一个应用程序,能够读取一个文本文件中的内容并显示,同时能够计算出文本中的行数。...
  7. GitFlow 工作流和Code Review教程
  8. 【图像处理】——傅里叶变换、DFT以及在图像上的应用
  9. jsp页面页面post传值_几种JSP页面传值方式
  10. 分享WordPress博客搜索引擎优化的六点经验
  11. 计算机课的情感目标是什么意思,教案中情感目标是什么.doc
  12. asterisk app命令中文翻译
  13. 用C#制作PDF文件全攻略
  14. ddl是什么意思网络语_ddl是什么意思(网络语ddl是什么梗)
  15. H5案例分享—你的数学是语文老师教的吗?
  16. JFinal在线官方文档
  17. oracle field怎么翻译,field是什么意思_field的翻译_音标_读音_用法_例句_爱词霸在线词典...
  18. mybatis-plus设置某个字段可以为空
  19. 对Java建造者模式(Builder)的一点理解
  20. 有关服务器的一些小问题

热门文章

  1. html5红外遥控,自己写的单片机万能红外遥控解码
  2. 双目测距 SGBM算法 Python版
  3. python opencv双目测距_OpenCV实现双目测距
  4. rms 公式 有效值_有效值、真有效值、基波有效值、全有效值概念辨析
  5. Involution Inverting the Inherence of Convolution for Visual Recognition
  6. python 加密文本_Python文件或文本加密(4种方法)
  7. apache Ignite 安装和helloworld
  8. PAT题集2019.6.5排名变动
  9. 互联网热门词汇搞笑来袭
  10. 《道德经》——《老子道德经》