Python实现Dijkstra算法找最短路径
“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《Python实现Dijkstra算法找最短路径》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!
Dijkstra算法适用于边权非负的图。1. 它不能处理含有负权边的图,因为一旦确定某个节点的最短路径,就不会再回头更新;2. 对于此类问题,更适合使用Bellman-Ford算法;3. Dijkstra适用于无向图和有向图,只要满足非负权边条件。
在Python中实现最短路径,Dijkstra算法是一个非常经典且高效的选择,尤其适用于边权非负的图。它的核心思想是逐步探索,每次都从已知最短路径的节点中,找到下一个距离起点最近的节点,然后以此更新其邻居的距离,直到所有可达节点的距离都被确定。

解决方案
实现Dijkstra算法,我们通常需要一个图的表示(比如邻接列表或字典),一个记录从起点到各节点当前最短距离的字典,一个记录路径前驱的字典,以及一个优先队列来高效地获取下一个要处理的节点。Python的heapq
模块非常适合做这个优先队列。
首先,我们得把图给搭起来。一个字典套字典的结构,或者用defaultdict(list)
来表示邻接列表,都挺直观的。我个人更倾向于后者,感觉在遍历邻居时更自然一些。

import heapq from collections import defaultdict def dijkstra(graph, start_node): # 存储从起点到各节点的最短距离 distances = {node: float('inf') for node in graph} distances[start_node] = 0 # 优先队列,存储 (距离, 节点) 对 # heapq 默认是最小堆,正好符合我们的需求 priority_queue = [(0, start_node)] # 存储路径的前驱节点,用于最终路径的重建 predecessors = {} while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) # 如果当前距离已经比记录的要长,说明我们找到了更短的路径,跳过 # 这是为了处理同一个节点可能被多次加入优先队列的情况 if current_distance > distances[current_node]: continue # 遍历当前节点的所有邻居 for neighbor, weight in graph[current_node].items(): # 假设graph是 {node: {neighbor: weight}} distance = current_distance + weight # 如果通过当前节点到达邻居的距离更短 if distance < distances[neighbor]: distances[neighbor] = distance predecessors[neighbor] = current_node # 更新前驱 heapq.heappush(priority_queue, (distance, neighbor)) return distances, predecessors def reconstruct_path(predecessors, start_node, end_node): path = [] current = end_node while current != start_node: if current not in predecessors: # 无法到达 return None path.insert(0, current) current = predecessors[current] path.insert(0, start_node) return path # 示例图 # graph = { # 'A': {'B': 1, 'C': 4}, # 'B': {'A': 1, 'C': 2, 'D': 5}, # 'C': {'A': 4, 'B': 2, 'D': 1}, # 'D': {'B': 5, 'C': 1} # } # 也可以这样表示,更通用一些,尤其是处理稀疏图时 graph_adj = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2, 'D': 5}, 'C': {'A': 4, 'B': 2, 'D': 1}, 'D': {'B': 5, 'C': 1} } start = 'A' end = 'D' shortest_distances, paths = dijkstra(graph_adj, start) print(f"从 {start} 到各节点的最短距离: {shortest_distances}") path = reconstruct_path(paths, start, end) print(f"从 {start} 到 {end} 的最短路径: {path}") # 输出示例: # 从 A 到各节点的最短距离: {'A': 0, 'B': 1, 'C': 3, 'D': 4} # 从 A 到 D 的最短路径: ['A', 'B', 'C', 'D']
这里有个小细节,graph[current_node].items()
假设了 graph
是一个字典,其值也是字典({node: {neighbor: weight}}
)。如果用邻接列表,比如 graph = {'A': [('B', 1), ('C', 4)]}
,那么遍历方式需要调整为 for neighbor, weight in graph[current_node]:
。我个人觉得字典嵌套字典更直观地表达了“从A到B的权重是多少”这种关系。
Dijkstra算法适用于哪些图类型?
Dijkstra算法最核心的适用条件,就是图中的所有边权重都必须是非负数。这是它的基石,如果图中存在负权边,Dijkstra算法就可能给出错误的答案。为什么会这样呢?因为Dijkstra算法在每次确定一个节点的最终最短距离后,就认为这个距离是“不可被超越”的了。它不会回头去检查,如果后面通过一条负权边,可能会让之前“确定”的最短路径变得更短。

举个例子,假设A到B是10,A到C是1,C到B是-100。Dijkstra会先确定A到C是1,然后用1去更新C的邻居。如果它先确定了A到B是10,然后就“锁死”了B的距离,但实际上A->C->B的路径是1 + (-100) = -99,比10短得多。这时候Dijkstra就傻眼了。
对于含有负权边的图,我们通常会考虑使用Bellman-Ford算法,它虽然时间复杂度更高,但能正确处理负权边,甚至能检测出负权环。不过,Dijkstra的优势在于其高效性,对于绝大多数实际应用中边权非负的场景,它都是首选。无论是无向图还是有向图,只要满足非负权边这个条件,Dijkstra都能胜任。
Dijkstra算法的时间复杂度是多少,如何优化?
Dijkstra算法的时间复杂度取决于图的表示方式和优先队列的实现。
如果使用朴素的数组来查找下一个最小距离的节点(即每次遍历所有未访问节点找到距离最小的那个),那么时间复杂度是 O(V^2),其中V是图中节点的数量。这种方式在节点数量不多的时候还能接受,但当V变得很大时,性能瓶颈就非常明显了。
当我们引入二叉堆(Binary Heap)作为优先队列时,时间复杂度可以显著优化到 O(E log V),其中E是图中边的数量。这里的log V
是每次从堆中取出最小元素或更新元素时,堆调整操作的开销。Python的heapq
模块底层就是基于二叉堆实现的,所以我们上面的代码就是这种优化过的版本。
更高级的优化,比如使用斐波那契堆(Fibonacci Heap),可以将时间复杂度进一步优化到 O(E + V log V)。不过,斐波那契堆的实现非常复杂,常数因子也比较大,所以在实际工程中,除非图的规模特别巨大且对性能有极致要求,否则通常还是使用基于二叉堆的Dijkstra算法。heapq
已经足够满足大部分需求了,它既简单易用,性能也相当不错。在大多数情况下,图的边数E通常比V的平方小得多(稀疏图),所以O(E log V)的性能提升是实实在在的。
在实际项目中,Dijkstra算法有哪些常见的应用场景?
Dijkstra算法在实际生活和技术领域中有着非常广泛的应用,它的核心价值在于找到“最优”或“最短”的连接方式,这在很多场景下都是关键。
最直观的,也是大家最熟悉的,就是GPS导航系统。当你输入目的地,导航软件计算出一条最优路线时,Dijkstra算法(或其变种,如A*算法,它在Dijkstra基础上加入了启发式搜索,进一步提升了效率)就在幕后默默工作。它将道路网络抽象成图,交叉路口是节点,路段是边,路段的长度或通行时间就是边的权重。
除了导航,它还在网络路由中扮演重要角色。互联网上的数据包需要从源头传输到目的地,路由器需要决定数据包的下一跳去哪里,以确保数据能以最快(或最经济)的方式抵达。OSPF(开放最短路径优先)等路由协议就使用了Dijkstra算法来计算网络拓扑中的最短路径。
在资源分配和调度方面,Dijkstra也能派上用场。比如,在物流配送中,如何规划送货车辆的路线,使其在最短时间内送达所有包裹;或者在云计算环境中,如何将任务分配给不同的服务器,以最小化处理时间或成本。这些都可以建模成最短路径问题。
甚至在游戏AI里,Dijkstra也有它的身影。比如,一个NPC(非玩家角色)需要从A点移动到B点,并避开障碍物,或者找到最近的补给点。游戏地图可以被视为一个网格图,Dijkstra可以帮助NPC规划出最佳的移动路径。
总的来说,任何可以被抽象成“在带权图中寻找最短路径”的问题,Dijkstra算法都值得被考虑。它的通用性和高效性,使得它成为了算法工具箱里不可或缺的一员。
本篇关于《Python实现Dijkstra算法找最短路径》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于文章的相关知识,请关注golang学习网公众号!

- 上一篇
- Java单例模式实现与对象唯一保障

- 下一篇
- abbr标签作用及SEO优化技巧
-
- 文章 · python教程 | 12分钟前 |
- Python中id的作用与对象识别解析
- 138浏览 收藏
-
- 文章 · python教程 | 16分钟前 |
- Python多列排序技巧:sort_values实用教程
- 406浏览 收藏
-
- 文章 · python教程 | 24分钟前 |
- Python中ans是什么意思及使用场景
- 344浏览 收藏
-
- 文章 · python教程 | 40分钟前 |
- Python图像处理性能优化与并发实战
- 476浏览 收藏
-
- 文章 · python教程 | 42分钟前 |
- Python自动化办公:pyautogui实战教程
- 371浏览 收藏
-
- 文章 · python教程 | 52分钟前 |
- YOLOv8图像尺寸适配解析与应用
- 392浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python操作Redis事务详解
- 141浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- PythonGUI自动化教程:PyAutoGUI使用详解
- 459浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- PythonPyqt5开发教程:桌面应用入门指南
- 146浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python计算百分比的实用方法
- 249浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 511次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 498次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 千音漫语
- 千音漫语,北京熠声科技倾力打造的智能声音创作助手,提供AI配音、音视频翻译、语音识别、声音克隆等强大功能,助力有声书制作、视频创作、教育培训等领域,官网:https://qianyin123.com
- 113次使用
-
- MiniWork
- MiniWork是一款智能高效的AI工具平台,专为提升工作与学习效率而设计。整合文本处理、图像生成、营销策划及运营管理等多元AI工具,提供精准智能解决方案,让复杂工作简单高效。
- 109次使用
-
- NoCode
- NoCode (nocode.cn)是领先的无代码开发平台,通过拖放、AI对话等简单操作,助您快速创建各类应用、网站与管理系统。无需编程知识,轻松实现个人生活、商业经营、企业管理多场景需求,大幅降低开发门槛,高效低成本。
- 126次使用
-
- 达医智影
- 达医智影,阿里巴巴达摩院医疗AI创新力作。全球率先利用平扫CT实现“一扫多筛”,仅一次CT扫描即可高效识别多种癌症、急症及慢病,为疾病早期发现提供智能、精准的AI影像早筛解决方案。
- 118次使用
-
- 智慧芽Eureka
- 智慧芽Eureka,专为技术创新打造的AI Agent平台。深度理解专利、研发、生物医药、材料、科创等复杂场景,通过专家级AI Agent精准执行任务,智能化工作流解放70%生产力,让您专注核心创新。
- 122次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览