【Python 算法】双向迪杰斯特拉算法 Python实现

双向迪杰斯特拉算法Python实现

文章目录

  • 双向迪杰斯特拉算法Python实现
    • 简介
    • 双向迪杰斯特拉算法优势
    • 局限性
    • 算法的基本步骤
      • 终止条件
    • 基本步骤
    • 伪代码
    • Python 实现
    • 双向迪杰斯特拉与单向迪杰斯特拉算法比较

简介

双向迪杰斯特拉算法(Bi Directional Dijkstra Algorithm)是一种用于在加权图中查找两个顶点之间最短路径的算法,是Dijkstra算法的一个变种,基本思想是:从两个搜索方向同时开始搜索——从起点到终点方向和从终点到起点方向同时进行迪杰斯特拉算法搜索,如果存在路径,那么最终两个方向的搜索会在某点相遇并终止,而这条路径就是最短距离路径。在某些情况下,双向迪杰斯特拉算法可以减少搜索空间大小,从而提高算法效率。其中也有分治法的思想

双向迪杰斯特拉算法优势

与迪杰斯特拉算法相比,双向迪杰斯特拉算法在以下情况更有优势:

  1. 大规模图搜索:如果图的规模很大,双向迪杰斯特拉算法很可能会比迪杰斯特拉算法更快。

  2. 稀疏图:在稀疏图中,双向迪杰斯特拉算法很可能会比迪杰斯特拉算法更快。

最主要是因为双向搜索可以减少一定的搜索空间,从终点开始搜索和从起点开始搜索,相当于做了一次剪枝。

image-20231113185857959

(我觉得这张图很形象的解释了为什么双向迪杰斯特拉算法能够减少搜索空间,而单项迪杰斯特拉算法在大规模图中,会越来越发散)

局限性

  1. 复杂性:双向迪杰斯特拉算法需要更复杂的数据结构来跟踪记录两个方向的搜索路径。算法需要更多时间维护两个方向的队列。
  2. 权重不均等的图、负权重图:对于边权重差异比较大和负权重的图,双向迪杰斯特拉算法可能不会表现得很好。
  3. 当终点和起点距离比较近的时候,双向迪杰斯特拉算法算法可能不如单项迪杰斯特拉算法算法。

但是双向迪杰斯特拉还是具有减少搜索空间更快搜索到最短路径的优点。

算法的基本步骤

终止条件

双向迪杰斯特拉算法最重要的是,终止条件,算法在什么时候应该终止,如何确定相遇的点是应该终止算法的。双向迪杰斯特拉算法需要维护两个队列,一个是从起点到终点方向的队列queue_from_startqueue_from_target,设: t o p f top_f topfqueue_from_start优先级队列的队头元素, t o p r top_r toprqueue_from_target优先队列的队头元素, μ \mu μ用来记录相遇点构成的路径值,初始化 μ = ∞ \mu = \infty μ=。在进行路径搜索的时候,当存在一条边 ( u , v ) (u,v) (u,v)满足 u u u在前向搜索中,而 v v v在反向搜索中,如果 d f ( u ) + c ( u , v ) + d r ( v ) < μ d_f(u)+c(u,v)+d_r(v) < \mu df(u)+c(u,v)+dr(v)<μ,则更新 μ \mu μ值。

终止条件: t o p f + t o p r ≥ μ top_f + top_r \ge \mu topf+toprμ

双向迪杰斯特拉算法

基本步骤

  1. 初始化:将起点加入到正向搜索的待处理队列中,将终点加入到反向搜索的待处理队列中。
  2. 迭代搜索:在每一次迭代中,算法分别对正向和反向的待处理队列中的顶点进行处理,选择当前距离最小的顶点进行扩展。
  3. 扩展顶点:对于选中的顶点,算法更新其邻接顶点的最短路径估计,并将这些邻接顶点加入到相应的待处理集合中。
  4. 检查相遇:在每次扩展后,算法检查正向和反向的搜索是否在某个顶点上相遇。相遇的条件通常是检查某个顶点是否同时出现在正向和反向的访问表中。
  5. 路径重构:一旦搜索相遇,算法使用正向和反向的路径信息来重构出从起点到终点的最短路径。
  6. 终止条件:如果两个搜索在中间某处相遇,或者一个方向的搜索已经找不到新的顶点进行扩展,算法终止。

伪代码

程序结构:

function BidirectionalDijkstra(graph, start, end)create priority queues queueFromStart, queueFromEndadd start to queueFromStart with priority 0add end to queueFromEnd with priority 0create distance maps distanceFromStart, distanceFromEnd and set all distances to infinityset distanceFromStart[start] to 0set distanceFromEnd[end] to 0create parent maps parentFromStart, parentFromEnd and set all parents to nullset parentFromStart[start] to startset parentFromEnd[end] to endwhile queueFromStart and queueFromEnd are not emptynodeFromStart = extract minimum from queueFromStartfor each neighbor of nodeFromStartif distance through nodeFromStart to neighbor is less than distanceFromStart[neighbor]update distanceFromStart[neighbor]update parentFromStart[neighbor]add neighbor to queueFromStart with priority distanceFromStart[neighbor]nodeFromEnd = extract minimum from queueFromEndfor each neighbor of nodeFromEndif distance through nodeFromEnd to neighbor is less than distanceFromEnd[neighbor]update distanceFromEnd[neighbor]update parentFromEnd[neighbor]add neighbor to queueFromEnd with priority distanceFromEnd[neighbor]if any node v is in both queueFromStart and queueFromEndpath = shortest path from start to v according to parentFromStartpath = path + reverse of shortest path from v to end according to parentFromEndreturn pathreturn no path

Python 实现

def bidirectional_dijkstra_b(graph, start, target, i):queue_from_start = []hq.heappush(queue_from_start, (0.0, start))distance_from_start = {node: float('infinity') for node in graph}distance_from_start[start] = 0.0parents_of_start = {start: None}queue_from_target = []hq.heappush(queue_from_target, (0.0, target))distance_from_target = {node: float('infinity') for node in graph}distance_from_target[target] = 0.0parents_of_target = {target: None}close_of_start = set()          # 访问禁闭表close_of_target = set()         # 访问禁闭表miu = math.infglobal nodenode = Nonewhile queue_from_start and queue_from_target:if queue_from_start[0][0] + queue_from_target[0][0] >= miu:return reverse_traversal(node, parents_of_start, parents_of_target)cur_dist, cur_node = hq.heappop(queue_from_start)close_of_start.add(cur_node)for adjacent, weight in graph[cur_node].items():if adjacent in close_of_start:continuedistance = cur_dist + weight["weight"]if distance < distance_from_start[adjacent]:distance_from_start[adjacent] = distanceparents_of_start[adjacent] = cur_nodehq.heappush(queue_from_start, (distance, adjacent))# 更新miu值if adjacent in close_of_target:dist = distance + distance_from_target[adjacent]if miu > dist:miu = distnode = adjacentcur_dist, cur_node = hq.heappop(queue_from_target)close_of_target.add(cur_node)for adjacent, weight in graph[cur_node].items():if adjacent in close_of_target:continuedistance = cur_dist + weight["weight"]if distance < distance_from_target[adjacent]:distance_from_target[adjacent] = distanceparents_of_target[adjacent] = cur_nodehq.heappush(queue_from_target, (distance, adjacent))if adjacent in close_of_start:dist = distance + distance_from_start[adjacent]if miu > dist:miu = distnode = adjacentreturn []

双向迪杰斯特拉与单向迪杰斯特拉算法比较

双向迪杰斯特拉算法写了两个版本,主要是控制方式不同。

实验中生成稀疏图标准是, e = n ∗ log ⁡ n e=n*\log{n} e=nlogn

test_result1 test_result

可以看出,随着节点和边的数量增多,算法的耗时越大,在节点数=50000,边数=252959时,迪杰斯特拉算法的速度远远高于双向迪杰斯特拉算法。

从上图来看,在50,500数量级的节点数下,第二种控制流的迪杰斯特拉算法更快,但是随着节点数数量级增大,第一种控制流双向迪杰斯特拉算法更优。推测结论:双向迪杰斯特拉算法是内含分治法思想的,如果两侧探索数量越均等越好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/174560.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解析SQL 获取表、字段及SQL查询参数

解析SQL 获取表、字段及SQL查询参数 1. 执行效果2. 使用2.1 引入依赖2.2 相关实体2.3 工具类 1. 执行效果 2. 使用 2.1 引入依赖 <!-- sql 解析处理--><dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifa…

【读点论文】结构化剪枝

结构化剪枝 在一个神经网络模型中&#xff0c;通常包含卷积层、汇合层、全连接层、非线形层等基本结构&#xff0c;通过这些基本结构的堆叠&#xff0c;最终形成我们所常用的深度神经网络。 早在 1998 年&#xff0c;LeCun 等人使用少数几个基本结构组成 5 层的 LeNet-5 网络&…

docker简介和安装

0.前提 本文章意在告诉各位开发者学生有一个工具能够方便你未来的项目开发和部署&#xff0c;这也是我在给我留下一份备份&#xff0c;在我忘记的时候可以回头寻找。 1.docker简介 docker本身就有集装箱的意思。Docker: Accelerated Container Application Development Dock…

香港科技大学广州|智能制造学域机器人与自主系统学域博士招生宣讲会—中国科学技术大学专场

&#x1f3e0;地点&#xff1a;中国科学技术大学西区学生活动中心&#xff08;一楼&#xff09;报告厅 【宣讲会专场1】让制造更高效、更智能、更可持续—智能制造学域 &#x1f559;时间&#xff1a;2023年11月16日&#xff08;星期四&#xff09;18:00 报名链接&#xff1a…

算法通关村第十六关青铜挑战——原来滑动窗口如此简单!

大家好&#xff0c;我是怒码少年小码。 从本篇开始&#xff0c;我们就要开始算法的新篇章了——四大思想&#xff1a;滑动窗口、贪心、回溯、动态规划。现在&#xff0c;向我们迎面走来的是——滑动窗口思想&#xff01;&#x1f61d; 滑动窗口思想 概念 在数组双指针里&am…

Java Stream 的使用

Java Stream 的使用 开始中间操作forEach 遍历map 映射flatMap 平铺filter 过滤limit 限制sorted 排序distinct 去重 结束操作collect 收集toList、toSet 和 toMapCollectors.groupingByCollectors.collectingAndThen metch 匹配find 查询findFirst 与 findAny 的使用Optional …

基于非对称纳什谈判的多微网电能共享运行优化策略(附带MATLAB程序)

基于非对称纳什谈判的多微网电能共享运行优化策略MATLAB程序 参考文献&#xff1a; 《基于非对称纳什谈判的多微网电能共享运行优化策略》——吴锦领 资源地址&#xff1a; 基于非对称纳什谈判的多微网电能共享运行优化策略MATLAB程序 MATLAB代码&#xff1a;基于非对称纳什…

SpringBoot3数据访问

SpringBoot3数据访问 SpringBoot整合 Spring、SpringMVC、MyBatis进行数据访问开发。 整合SSM场景 整合步骤 1、创建SSM整合项目 ①数据库准备 DROP TABLE IF EXISTS t_user; CREATE TABLE t_user (id bigint NOT NULL AUTO_INCREMENT COMMENT 编号,login_name varchar(200)…

[Linux]tcpdump抓包工具

windows中的抓包工具&#xff1a;wireshark linux中的抓包工具&#xff1a;tcpdump cpdump是Linux系统中自带抓包工具 [rootIKUN ~]# rpm -q tcpdump tcpdump-4.9.0-5.el7.x86_64 [rootIKUN ~]# tcpdump tcp -i ens33 -t -s 0 -c 100 and dst port ! 22 and src net 192.1…

又卷又累,救救一个将被随机拖死的程序员!

前两天在小红书上看到有人吐槽&#xff1a;“国内做程序员性价比不高&#xff0c;又卷又累&#xff0c;个人时间都被拖死了。” 现在普遍来讲&#xff0c;“卷”都是打工人的现状。 而至于国内程序员性价比不高的话&#xff0c;确实是肉少僧多。工作强度一加持&#xff0c;累自…

使用jedis连接虚拟机redis报错 Failed to connect to any host resolved for DNS name

问题描述&#xff1a; 导致该问题发生的原因可能是虚拟机没有开放6379端口。 解决方案&#xff1a; 首先检查redis.conf的bing配置是否被注释了&#xff0c;如果没有将其注释 第二步&#xff0c;将保护模式设置为no 第三步&#xff0c;接下来可以使用命令查看6379端口是否…

Java学习之路 —— Day3(内部类、枚举、泛型、API)

文章目录 1. 内部类2. 枚举3. 泛型 1. 内部类 成员内部类 就是类中的一个普通成员&#xff0c;类似普通的成员方法、成员变量。&#xff08;套娃&#xff09; public class Outer {public class Inner {private String name;public static String school;public String getNa…