算法简介

狄克斯特拉算法(Dijkstra )用于计算出不存在非负权重的情况下,起点到各个节点的最短距离

可用于解决2类问题:

  • 从A出发是否存在到达B的路径;
  • 从A出发到达B的最短路径(时间最少、或者路径最少等),事实上最后计算完成后,已经得到了A到各个节点的最短路径了;

其思路为:

(1) 找出“最便宜”的节点,即可在最短时间内到达的节点。

(2) 更新该节点对应的邻居节点的开销,其含义将稍后介绍。

(3) 重复这个过程,直到对图中的每个节点都这样做了。

(4) 计算最终路径。

案例

案例一

先举个简单的例子介绍其实现的思路:

如下图按Dijkstra算法思路获取起点到终点的最短路径

1.首先列出起点到各个节点耗费的时间:

父节点 节点 耗时
起点 A 6分钟
起点 B 2分钟
.. 终点 ∞当做无穷大

2.获取最便宜的节点,由上表知道,起点->B花费最少,计算节点B前往各个邻居节点所需要的时间,并更新原本需要花费更多的时间的节点:

父节点 节点 耗时
B A 5分钟 更新耗时,原本需要6分钟
起点 B 2分钟
B 终点 7分钟 更新耗时

3.此时B添加进已处理的列表,不再处理了,现在只剩起点->A花费最少,计算节点A前往各个邻居节点所需要的时间,并更新原本需要花费更多的时间的节点:

父节点 节点 耗时
- A 5分钟 更新耗时,原本需要6分钟
起点 B 2分钟
A 终点 6分钟 更新耗时,原本需要7分钟

4.此时通过倒序可以知道: 起点 -> A -> 终点 , 该路径即为最短的路径,耗费6分钟

案例二

这边以之前的广度优先搜索算法的例子进行举例:

如上图所示,前边使用广度优先搜索算法可以得知A到H所需要的最少步骤的路径为: A->B->E->H, 本次在各个路径上添加所需花费的时间(当然代表公里数之类的也行),作为各个路段的权重。

现在A->B->E->H明显就不再是花费时间最短的路线了,这种添加了权重求最短路径的问题,可以使用狄克斯特拉算法来解决:

1.获取A到各个节点的耗时,A标志为已处理:

父节点 节点 耗时
A B 5分钟
A C 1分钟
.. H ∞当做无穷大

2.找出A能到达的最短的节点,计算更新相邻节点的耗时,此时最短的节点为C,C标志为已处理

父节点 节点 耗时 标志
A B 5分钟  
A C 1分钟 C已处理
C D 6分钟  
C F 7分钟  
.. H ∞当做无穷大  

2.找出A能到达的最短的节点,计算更新相邻节点的耗时,此时最短的节点为B,B标志为已处理

父节点 节点 耗时 标志
A B 5分钟 B已处理
A C 1分钟 C已处理
C D 6分钟  
C F 7分钟  
B E 15分钟  
.. H ∞当做无穷大  

3.A相邻节点已处理完,此时找出C能到达的最短的节点,此时为C->D,计算更新相邻节点的耗时,D标志为已处理

父节点 节点 耗时 标志
A B 5分钟 B已处理
A C 1分钟 C已处理
C D 6分钟 D已处理
C F 7分钟  
D E 9分钟  
.. H ∞当做无穷大  

4.同理更新 F

父节点 节点 耗时 标志
A B 5分钟 B已处理
A C 1分钟 C已处理
C D 6分钟 D已处理
C F 7分钟 F已处理
D E 9分钟  
F G 9分钟  
.. H ∞当做无穷大  

4.同理更新 E

父节点 节点 耗时 标志
A B 5分钟 B已处理
A C 1分钟 C已处理
C D 6分钟 D已处理
C F 7分钟 F已处理
D E 9分钟 E已处理
F G 9分钟  
E H 12分钟  

5.同理更新 G

父节点 节点 耗时 标志
A B 5分钟 B已处理
A C 1分钟 C已处理
C D 6分钟 D已处理
C F 7分钟 F已处理
D E 9分钟 E已处理
F G 9分钟 G已处理,G->H并没有降低花费,所以不更新H耗时
E H 12分钟  

经过如上步骤后边可以通过倒序得到最短路径为:

A->H的最短路径为:A->C->D->E->H ,总耗时12分钟; 表中其余结果也是最短路径了,比如A->G最短路径: A->C->F->G

局限性

该算法不适合负权重的情况,案例三:

这边使用该算法看看为何不适合,计算A->E:

1.首先起点A出发

父节点 节点 耗时
A B 100元
A C 1元
.. 终点 ∞当做无穷大

2.计算最便宜节点C

父节点 节点 耗时 标志
A B 100元  
A C 1元 C已处理
C D 2元  
.. 终点 ∞当做无穷大  

2.计算最便宜节点B

父节点 节点 耗时 标志
A B 100元 B已处理
B C -100元 C已处理,但是这边依旧需要更新了C
C D 2元  
.. 终点 ∞当做无穷大  

3.计算最便宜节点D

父节点 节点 耗时 标志
A B 100元 B已处理
B C -100元 C已处理,但是这边依旧需要更新了C
C D 2元 D已处理
D E 3元  

使用 Dijkstra算法计算出来结果将是错误的A->C->D->E,耗费3元,在 狄克斯拉算法中被标志位已处理的节点,便代表中不存在其它到达该节点更便宜的路径了,由于负权重的引入导致了该原则不成立,上述中由于C节点已经被处理过了,结果又需要再次更新C的内容,但对应的此时C后续的子节点比如D可能存在未同步更新的情况,从而导致最终的结果错误。当然也有可能碰巧算对的情况,比如上述案例二中修改A->B = -50的话 , 可以计算出正确的最短路线为A --> B --> E --> H 耗费-37。

个人感觉能不能碰巧算对就看是不是负权重再次更新的节点是不是尚未计算相邻节点了,比如案例三B优先于C处理:

处理B:

父节点 节点 耗时 标志
A B 100元 B已处理
A C -100元  
.. 终点 ∞当做无穷大  

处理C:

父节点 节点 耗时 标志
A B 100元 B已处理
A C -100元 C已处理
C D -99元  
.. 终点 ∞当做无穷大  

处理D:

父节点 节点 耗时 标志
A B 100元 B已处理
A C -100元 C已处理
C D -99元 D已处理
D E -98元  

此时正确路径 A->->C->D->E,倒赚98元

但是这么做已经和Dijkstra相违背了,在某些情况下可能出现效率极低的现象。所有Dijkstra算法不应该被用于负权重的情况下。

小结

1.广度优先算法BFS主要适用于无权重向图重搜索出步骤最少的路径,当方向图存在权重时,不再适用

2.狄克斯特拉算法Dijkstra主要用于有权重的方向图中搜索出最短路径,但不适合于有负权重的情况.对于环图,个人感觉和BFS一样,标志好已处理的节点避免进入死循环,可以支持

3.算法的实现主要都是为了避免没有更好的解决办法,而采用穷举法进行解决,当节点数量极大的情况下,算法的优势就会突显出来

java实现

/*** 狄克斯特拉算法* @author Administrator**/
public class Dijkstra {public static void main(String[] args){HashMap<String,Integer> A = new HashMap<String,Integer>(){{put("B",5);put("C",1);}};HashMap<String,Integer> B = new HashMap<String,Integer>(){{put("E",10);}};HashMap<String,Integer> C = new HashMap<String,Integer>(){{put("D",5);put("F",6);}};HashMap<String,Integer> D = new HashMap<String,Integer>(){{put("E",3);}};HashMap<String,Integer> E = new HashMap<String,Integer>(){{put("H",3);}};HashMap<String,Integer> F = new HashMap<String,Integer>(){{put("G",2);}};HashMap<String,Integer> G = new HashMap<String,Integer>(){{put("H",10);}};HashMap<String,HashMap<String,Integer>> allMap = new HashMap<String,HashMap<String,Integer>>() {{put("A",A);put("B",B);put("C",C);put("D",D);put("E",E);put("F",F);put("G",G);}};Dijkstra dijkstra = new Dijkstra();dijkstra.handle("A","H",allMap);}private String  getMiniCostKey(HashMap<String,Integer> costs,List<String> hasHandleList) {int mini = Integer.MAX_VALUE;String miniKey = null;for(String key : costs.keySet()) {if(!hasHandleList.contains(key)) {int cost = costs.get(key);if(mini > cost) {mini = cost;miniKey = key;}}}return miniKey;}private void handle(String startKey,String target,HashMap<String,HashMap<String,Integer>> all) {//存放到各个节点所需要消耗的时间HashMap<String,Integer> costMap = new HashMap<String,Integer>();//到各个节点对应的父节点HashMap<String,String> parentMap = new HashMap<String,String>();//存放已处理过的节点key,已处理过的不重复处理List<String> hasHandleList = new ArrayList<String>();//首先获取开始节点相邻节点信息HashMap<String,Integer> start = all.get(startKey);//添加起点到各个相邻节点所需耗费的时间等信息for(String key:start.keySet()) {int cost = start.get(key);costMap.put(key, cost);parentMap.put(key,startKey);}//选择最"便宜"的节点,这边即耗费时间最低的String minCostKey = getMiniCostKey(costMap,hasHandleList);while( minCostKey!=null ) {System.out.print("处理节点:"+minCostKey);HashMap<String,Integer> nodeMap = all.get(minCostKey);if (nodeMap!=null) {//该节点没有子节点可以处理了,末端节点handleNode(minCostKey,nodeMap,costMap,parentMap);}//添加该节点到已处理结束的列表中hasHandleList.add(minCostKey);//再次获取下一个最便宜的节点minCostKey = getMiniCostKey(costMap,hasHandleList);}if(parentMap.containsKey(target)) {System.out.print("到目标节点"+target+"最低耗费:"+costMap.get(target));List<String> pathList = new ArrayList<String>();String parentKey = parentMap.get(target);while (parentKey!=null) {pathList.add(0, parentKey);parentKey = parentMap.get(parentKey);}pathList.add(target);String path="";for(String key:pathList) {path = path + key + " --> ";}System.out.print("路线为"+path);} else {System.out.print("不存在到达"+target+"的路径");}}private void handleNode(String startKey,HashMap<String,Integer> nodeMap,HashMap<String,Integer> costMap,HashMap<String,String> parentMap) {for(String key : nodeMap.keySet()) {//获取原本到父节点所需要花费的时间int hasCost = costMap.get(startKey);//获取父节点到子节点所需要花费的时间int cost = nodeMap.get(key);//计算从最初的起点到该节点所需花费的总时间cost = hasCost + cost;if (!costMap.containsKey(key)) {//如果原本并没有计算过其它节点到该节点的花费costMap.put(key,cost);parentMap.put(key,startKey);}else {//获取原本耗费的时间int oldCost = costMap.get(key);if (cost < oldCost) {//新方案到该节点耗费的时间更少//更新到达该节点的父节点和消费时间对应的散列表costMap.put(key,cost);parentMap.put(key,startKey);System.out.print("更新节点:"+key + ",cost:" +oldCost + " --> " + cost);}}}}
执行完main方法打印信息如下:处理节点:C处理节点:B处理节点:D更新节点:E,cost:15 --> 9处理节点:F处理节点:E处理节点:G处理节点:H到目标节点H最低耗费:12路线为A --> C --> D --> E --> H

微信公众号:

算法(四):图解狄克斯特拉算法相关推荐

  1. 算法图解-狄克斯特拉算法

    本章内容: 加权图-提高或者降低某些边的权重 狄克斯特拉算法,能找出加权图中前往x的最短路径 图中的环,它导致狄克斯特拉算不管用 7.1狄克斯特拉算法 4个步骤: 找出最便宜的节点,即最短时间内前往的 ...

  2. 算法学习之狄克斯特拉算法

    加权图 在了解狄克斯特拉算法之前,先介绍一下加权图. 如图,假设你要从起点出发到达终点,如果只考虑换乘少,即最短路径.那么可以使用广度优先搜索算法,该算法我之前简单的写过,链接点这里.但是,现在你要找 ...

  3. 算法笔记之狄克斯特拉算法

    算法笔记第七章: 1.狄克斯特拉算法->找出加权图中前往X的最短路径: 2.加权图:(带权重的图) 3.迪克斯特拉算法步骤: x.找出最便宜的节点,即可最短时间内到达的节点:x.更新该节点的邻居 ...

  4. 算法图解第七章狄克斯特拉算法读书笔记

    广度优先搜索找出的是段数最少的路径;狄克斯特拉算法找出最快的路径. 狄克斯特拉算法包含4个步骤: 1)找出"最便宜"的节点,即可在最短时间内到达的节点. 2)更新该节点的邻居的开销 ...

  5. 最短路-弗洛伊德算法狄克斯特拉算法

    最短路 1.多源最短路 定义:现有n个地点,求任意两点间的最短距离 算法:弗洛伊德(floyd)算法 思想:让每一个点成为中转点,进行"松弛"操作: 所谓松弛操作就是要搞出 A+B ...

  6. 《算法图解》学习笔记(七):狄克斯特拉算法(附代码)

    欢迎关注WX公众号:[程序员管小亮] python学习之路 - 从入门到精通到大师 文章目录 欢迎关注WX公众号:[程序员管小亮] [python学习之路 - 从入门到精通到大师](https://b ...

  7. 算法图解part7:狄克斯特拉算法

    算法图解part7:狄克斯特拉(Dijkstra)算法 1.狄克斯特拉算法(Dijkstra's algorithm) 2.术语 3.负权边 4.实现狄克斯特拉算法 4.1 最短路径思路 4.2 py ...

  8. 《算法图解》——狄克斯特拉算法

    前面文章提到,找出段数最少的路径,使用广度优先搜索. 现在要找出最快的路径,(花费最少)使用狄克斯特拉算法. 狄克斯特拉算法包含的四个步骤: (1)找出最便宜的节点,即可在最短时间内前往的节点. (2 ...

  9. 算法之狄克斯特拉算法 --《图解算法》

    2019你好!好好生活,好好工作! 狄克斯特拉算法 狄克斯特拉算法(Dijkstra )用于计算出不存在非负权重的情况下,起点到各个节点的最短距离 可用于解决2类问题: 从A出发是否存在到达B的路径: ...

最新文章

  1. oracle存储过程dbms_output.put_line()显示打印结果
  2. SQLSERVER监控复制并使用数据库邮件功能发告警邮件
  3. 图片上传成功但是图片显示不出来_小程序上传图片到腾讯云
  4. android控件---自定义带文本的ImageButton
  5. c语言扫雷游戏代码_C语言游戏详解---扫雷游戏
  6. php 精品课程,php51精品课程高级版
  7. 数据模型与决策_数据模型与决策复习资料拿走不用客气
  8. go 结构体排序的几种方法
  9. 【转】.NET框架简介
  10. java indexof方法_【3-14】Java中集合类list的增删改查
  11. Docker基础入门总结
  12. 2014C++A:蚂蚁感冒(数组+判断)
  13. Wrise - 与众不同的文字编辑器
  14. 常见 MIME 类型列表
  15. elasticsearch-6.1.2 x-pack java transport client客户端连接
  16. 线下门店如何实现增长获客?
  17. 基于Python的指数基金量化投资 - 指数的净资产收益率计算
  18. HarmonyOS APP开发入门3——组件(二 Text组件)
  19. win10无线网卡无法连接网络
  20. Java Web小课程3——写servlet

热门文章

  1. leetcode题目及答案python_leetcode Python算法题(20)-----多题
  2. STM8单片机通过PWM触发ADC同步采样
  3. 485通信实现自动收发功能
  4. 毕设日志——TensorFlow安装的numpy覆盖?掉了pytorch的numpy
  5. 吴恩达深度学习2.1练习_Improving Deep Neural Networks_initialization
  6. Windows下使用emacs+cscope
  7. 字节流转换为对象的方法
  8. Spring Cloud Spring Boot mybatis分布式微服务云架构(五)构建RESTful API
  9. Testin云測试破7000万次:崩溃成90%手游应用质量难题
  10. 解决AutoCAD acmgd.dll ARX命令中发现异常