上一篇文章,我们了解了广度优先搜索算法(BFS),BFS主要用来解决图的可达路径验证和最小路径问题,即从一个顶点A到另一个顶点B,是否有可达路径,如果有那么求出其到达的最少步骤。那么这里的最短路径就如果加上时间或者其他元素来表示的话,真的就是最短的吗?

这里,我们不妨将达到各个顶点的边加上一个花费时间来修饰,这里用来修饰边的元素,我们称之为权重,加上权重的边即为加权边,如下图所示:


还是上一篇文章的图,但是我们做了一些改动,这里我们使用有向图并且给各个边加上了权重,这里的权重代表的是每条边需要花费的时间,这样一来,我们上一篇文章中求出的 “最短路径” 还合适吗?

一目了然,加上权重之后,我们之前的最短路径已经不是真的 “最短”,那么我们需要引入一个专门的算法来处理这种情况——狄克斯特拉算法

算法简介

狄克斯特拉算法 是用来处理加权图的最短路径问题的一种图遍历算法,其具体思路如下:

  1. 找出 “最便宜” 的节点,即可在最小权重下到达的节点;
  2. 更新该节点的邻居的开销;
  3. 重复这个过程,直到对图中所有的节点都这样做了。
  4. 计算最终的路径

我们来看使用这种思路,解决上图的最短路径问题,分步拆解如下:

第一步:

从起点 Start出发,找出它能到达的最便宜的节点,从图中看出,节点Start相邻的节点有A 和 B,到达A节点需要5分钟,到达B节点需要 2分钟,至于其他节点对于Start节点来说目前并不清楚,我们假设为无穷大,我们用一个节点开销表来表示,如下所示:

节点 耗时
A 5
B 2
C ∞\infty∞
D ∞\infty∞
E ∞\infty∞
F ∞\infty∞
End ∞\infty∞

第二步:

由上表我们知道Start节点到B节点的开销最低为2,那么更新B节点的开销为2,我们用一个节点-开销表来表示其中的关系,如下表所示:

父节点 节点 开销
Start A 5
Start B 2

接着我们从B节点出发找最便宜开销节点,如下表所示:

节点 开销
D 2
E 7

那么我们修改B的邻居节点的开销为:

父节点 节点 开销
B D 5
B E 9

第三步:

接着重复上述步骤,直到得到如下表格:

父节点 节点 开销
Start B 2
B D 5
D C 6
C End 8

代码实现

Python实现

def find_lowest_cost_node(costs,processed):lowest_cost = float('inf')  # 默认节点开销为无穷大lowest_cost_node = None   # 默认最小开销节点为Nonefor node in costs:cost = costs[node]  # 当前节点开销if cost < lowest_cost and node not in processed:lowest_cost = costlowest_cost_node = nodereturn lowest_cost_nodedef dijkstra(start,end,graph):costs = graph[start]  # 起点到邻居节点的开销映射parents = {}  # 保存最小开销节点与父节点的关系映射processed = []  # 已处理节点列表,防止节点重复处理# 查找起点可以到达的最小开销节点node = find_lowest_cost_node(costs,processed)while node is not None:cost = costs[node]  # neighbors = graph[node]  # 当前最小开销节点的邻居节点for next_node in neighbors.keys():# 从最小开销节点到达其邻居节点的合并开销new_cost = cost + neighbors[next_code]if next_node not in costs or costs[next_code] > new_cost:costs[next_code] = new_costparents[next_code] = nodeprocessed.append(node)node = find_lowest_cost_node(costs,processed)path = [end]  # 最短路径节点列表parent = parents[end]while parent:if parent == start:path.append(parent)breakpath.append(parent)if parent in parents.keys():parent = parents[parent]else:breakpath.append(start)  # 加入起点print('最短路径为 %s' % (' -> '.join(path[::-1])))print('最小开销为: %d' % costs[end])if __name__ == '__main__':graph = dict()graph['Start'] = dict()graph['Start']['A'] = 5graph['Start']['B'] = 2graph['A'] = dict()graph['A']['C'] = 3graph['B'] = dict()graph['B']['D'] = 3graph['B']['E'] = 7graph['C'] = dict()graph['C']['End'] = 1graph['D'] = dict()graph['D']['C'] = 1graph['E'] = dict()graph['E']['F'] = 2graph['F'] = dict()graph['F']['End'] = 1graph['End'] = {}dijkstra('Start', 'End', graph)

输出结果:

最短路径为: Start -> B -> D -> C -> End
最小开销为:  7

Java实现

//查找开销最小的节点
private String findLowestCostNode(Map<String,Integer> costs,Set<String> processed) {int lowestCost = Integer.MAX_VALUE;String lowestCostNode = null;for (String node : costs.keySet()) {int cost = costs.get(node);if (cost < lowest_cost && !processed.contains(node)) {lowest_cost = cost;lowest_cost_node = node;}}return lowest_cost_node;
}/*** 使用狄克斯特拉算法查找加权边最优路径* @param start  起点* @param end   终点* @param graph  图结构散列表*/
public  void search(String start,String end,Map<String,Map<String,Integer>> graph) {//起点的邻居节点的开销映射Map<String, Integer> costs = graph.get(start);//各个最小开销节点的父节点Map<String,String> parents = new HashMap<>();//已处理节点的集合Set<String> processed = new HashSet<>();//查找起点可达的最小开销节点String node = findLowestCostNode(costs,processed);while (node != null && graph.get(node) != null) {int cost = costs.get(node);Map<String,Integer> neighbors = graph.get(node);for (String n : neighbors.keySet()) {int new_cost = cost + neighbors.get(n);if (!costs.containsKey(n) || costs.get(n) > new_cost) {costs.put(n,new_cost);parents.put(n,node);}}processed.add(node);node = findLowestCostNode(costs,processed);}print(start,end,parents,costs.get(end));
}private void print(String start,String end,Map<String,String> parents,int cost) {Stack<String> stack = new Stack<>();String parent = parents.get(end);while (parent != null) {if (start.equalsIgnoreCase(parent)) {stack.push(parent);break;}stack.push(parent);parent = parents.get(parent);}StringBuffer path = new StringBuffer();while (!stack.empty()) {String node = stack.pop();if (path.length != 0) {path.append(" -> ");}path.append(node);}System.out.println("最优路径: " + start + " -> " + path.toString() + " -> " + end);System.out.println("总开销为: " + cost);
}

算法详解之狄克斯特拉算法相关推荐

  1. 小白的算法初识课堂(part7)--狄克斯特拉算法

    学习笔记 学习书目:<算法图解>- Aditya Bhargava 文章目录 狄克斯特拉算法 具体步骤实现 术语 跳蚤市场 具体步骤实现 负权边 python实现 狄克斯特拉算法 在上一个 ...

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

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

  3. Python查找算法之狄克斯特拉算法

    目录 简介 加权图 非加权图 思路 实例 代码步骤 代码示例 运行结果 简介 狄克斯特拉算法解决了耗时最短(总权重最小)问题狄克斯特拉算法适用于加权图,并且图为有向无环图(DAG),而且权重不能为负数 ...

  4. 狄克斯特拉算法(入门)

    狄克斯特拉算法可以找出加权图中前往X的最短路径. 注意: - 其只适用于有向无环图 - 适用于正权边,负权边的将出错(贝尔曼-福德算法适用于负权边) 步骤: 找出当前最"便宜"的节 ...

  5. 图解算法学习笔记(七):狄克斯特拉算法

    目录 1)使用狄克斯特拉算法 2)术语 3)实现 4)小结 本章内容; 介绍加权图,提高或降低某些边的权重: 介绍狄克斯特拉算法,找出加权图中前往X的最短路径: 介绍图中的环,它导致狄克斯特拉算法不管 ...

  6. 算法(四):图解狄克斯特拉算法

    算法简介 狄克斯特拉算法(Dijkstra )用于计算出不存在非负权重的情况下,起点到各个节点的最短距离 可用于解决2类问题: 从A出发是否存在到达B的路径: 从A出发到达B的最短路径(时间最少.或者 ...

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

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

  8. 算法图解之狄克斯特拉算法实现

    狄克斯特拉算法用于在加权图中查找最短路径(权重不能为负) '''实现狄克斯特拉算法''' graph = {} graph['start'] = {}#在散列表graph中再建一个散列表为start, ...

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

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

最新文章

  1. OUTER在mysql_MySQL不支持OUTER APPLY
  2. rails安装与卸载
  3. .NET重构—单元测试的代码重构
  4. 我的心底装着宽恕和包容世界很美
  5. Android Studio中安装OpenCV SDK
  6. 多个mysql 环境_关于几个MySQL环境问题的对比
  7. 【转】C++中的static_cast ,reinterpret_cast的用法和区别
  8. 天池 在线编程 三等分(模拟)
  9. 分析原因型思维模型框架_分析营销型网站优化效果不佳的主要原因
  10. Hibernate框架 主配置文件 Hibernate.cfg.xml 映射配置 说明
  11. python必备基础代码-Python基础练习之用户登录实现代码分享
  12. [HihoCoder1369]网络流一·Ford-Fulkerson算法
  13. JAVA:获得当前执行路径的办法
  14. 给产品经理讲技术:微信的openid和unionid
  15. 新版三证合一营业执照组织机构代码是哪9位及统一社会信用代码怎么获取9位全国企业组织机构代码查询入口
  16. PLS-00103: Encountered the symbol “DECLARE“
  17. Arduino:设置ADC参考电压
  18. vba 批量生成条形图代码
  19. C语言学生成绩管理系统——检查学号姓名,双向循环链表
  20. vs2005 sp1补丁安装,报1718错误: 数字签名拒绝

热门文章

  1. 原型软件--Balsamiq Mockups
  2. vs 2010 sp1 中文版 安装sliverlight 5 正式版
  3. typescript学习之函数
  4. 公募“一哥”王亚伟已在深圳前海低调复出
  5. linux mint 下载迅雷安装包,Linux Mint如何安装“微信、QQ、迅雷、WPS办公软件”等国内上瘾软件...
  6. 人工智能---深度学习是什么
  7. Linux开关键盘背光灯
  8. 神经网络训练样本太少,神经网络常用训练方法
  9. 【MySQL】SHOW WARNINGS和SHOW ERRORS的作用是什么?
  10. txt文件中生成立体字或图案网站