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

news2024/11/20 12:24:21

双向迪杰斯特拉算法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, queueFromEnd
    add start to queueFromStart with priority 0
    add end to queueFromEnd with priority 0
    create distance maps distanceFromStart, distanceFromEnd and set all distances to infinity
    set distanceFromStart[start] to 0
    set distanceFromEnd[end] to 0
    create parent maps parentFromStart, parentFromEnd and set all parents to null
    set parentFromStart[start] to start
    set parentFromEnd[end] to end

    while queueFromStart and queueFromEnd are not empty
        nodeFromStart = extract minimum from queueFromStart
        for each neighbor of nodeFromStart
            if 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 queueFromEnd
        for each neighbor of nodeFromEnd
            if 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 queueFromEnd
            path = shortest path from start to v according to parentFromStart
            path = path + reverse of shortest path from v to end according to parentFromEnd
            return path

    return 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.0
    parents_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.0
    parents_of_target = {target: None}

    close_of_start = set()          # 访问禁闭表
    close_of_target = set()         # 访问禁闭表

    miu = math.inf
    global node
    node = None

    while 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:
                continue
            distance = cur_dist + weight["weight"]

            if distance < distance_from_start[adjacent]:
                distance_from_start[adjacent] = distance
                parents_of_start[adjacent] = cur_node
                hq.heappush(queue_from_start, (distance, adjacent))
                # 更新miu值
                if adjacent in close_of_target:
                    dist = distance + distance_from_target[adjacent]
                    if miu > dist:
                        miu = dist
                        node = adjacent
                        
        cur_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:
                continue
            distance = cur_dist + weight["weight"]
            if distance < distance_from_target[adjacent]:
                distance_from_target[adjacent] = distance
                parents_of_target[adjacent] = cur_node
                hq.heappush(queue_from_target, (distance, adjacent))

                if adjacent in close_of_start:
                    dist = distance + distance_from_start[adjacent]
                    if miu > dist:
                        miu = dist
                        node = adjacent
                       
    return []

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6 Spring循环依赖

什么是循环依赖&#xff1f; // A依赖了B class A{ public B b; } // B依赖了A class B{ public A a; } 如果不考虑Spring&#xff0c;循环依赖并不是问题&#xff0c;因为对象之间相互依赖是很正常的事情 A a new A(); B b new B(); a.b b; b.a a; 这样&#xff0c;A&a…

初认识vue,v-for,v-if,v-bind,v-model,v-html等指令

vue 一.vue3介绍 1.为什么data是函数而不是对象? 因为vue是组件开发,组件会多次复用,data如果是对象,多次复用是共享,必须函数返回一个新的对象 1. 官网初识 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS …

stm32控制舵机sg90

一、sg90简介 首先介绍说一下什么是舵机。舵机是一种位置&#xff08;角度&#xff09;伺服的驱动器。适用于一些需要角度不断变化的&#xff0c;可以保持的控制系统。sg90就是舵机的一种。 舵机的工作原理比较简单。舵机内部有一个基准电压&#xff0c;单片机产生的PWM信号通…

postswigger 靶场(CSRF)攻略-- 3.令牌验证

靶场地址&#xff1a; https://portswigger.net/web-security/csrf 令牌(token) 验证取决于令牌(token) 的存在 题目中已告知易受攻击的是电子邮件的更改功能&#xff0c;而目标是利用 csrf 漏洞更改受害者的电子邮件地址&#xff0c;最后给出了登录凭据&#xff1a;wiener:pet…

接口优化技巧,确实很优雅

针对疫情影响企业收入资源短缺一些老项目,做了许多降本增效的事情,其中发现最多的就是接口耗时过长的问题,就集中搞了一次接口性能优化。 二、接口优化方案执行 1、批处理 批量思想:批量操作数据库,项目往往有需要批量插入操作,比如商品,品格,价格等,可以在批处理执…

计算机毕业设计 基于Vue篮球联盟管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

YOLO的bounding boxes

YOLO使用了 77 网格 (SS)、2 个bounding boxes (B2) 和 20 个类别 ©。 1.YOLO将输入的图片resize成448 x 448&#xff0c;并且为 S x S&#xff08;S 7&#xff09;个grid&#xff0c;如果物体的中心落入该grid中&#xff0c;那么该grid就需要负责检测该物体。 2.对于每…

行业寒冬下,给软件测试工程师or功能测试的一些建议

​行业寒冬下&#xff0c;给软件测试工程师的一些建议 【文章末尾给大家留下了大量的福利】 国内的互联网行业发展较快&#xff0c;所以造成了技术研发类员工工作强度比较大&#xff0c;同时技术的快速更新又需要员工不断的学习新的技术。因此淘汰率也比较高&#xff0c;超过…

No191.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

时钟丢失监控机制

文章目录 前言一、分析芯片手册1、6.2.4 Clock monitoring2、28.1.5 System clock and clock monitor requirement3、分析寄存器1) SCG_SOSCCSR[SOSCCM]2) SCG_SOSCCSR[SOSCCMRE] 二、EB配置1、检查复位源2、配置时钟监控 三、结果验证总结 前言 本文章主要基于恩智浦 S32K14x…

【代码随想录】算法训练计划20

1、654. 最大二叉树 题目&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建…

LEEDCODE 75颜色分类

耍赖皮写法 嘻嘻 class Solution { public:void sortColors(vector<int>& nums) {int count1 0;int count2 0;int count3 0;for(int i 0; i<nums.size(); i){if(nums[i] 0)count1 1;else if(nums[i] 1)count2 1;else count3 1;}for(int i 0; i<nu…

如何使用内网穿透实现远程公网访问windows node.js的服务端

使用Nodejs搭建简单的web网页并实现公网访问 前言 Node.js是建立在谷歌Chrome的JavaScript引擎(V8引擎)的Web应用程序框架。 Node.js自带运行时环境可在Javascript脚本的基础上可以解释和执行(这类似于JVM的Java字节码)。这个运行时允许在浏览器以外的任何机器上执行JavaScri…

达索系统3DEXPERIENCE WORKS 2024流体仿真功能增强

设计工作中&#xff0c;网格划分和设计验证十分重要&#xff0c;它可以方便我们把复杂组件简单化处理&#xff0c;从而提升工作效率。 轻松应对&#xff0c;精准划分 在优化设计以获得更好的空气动力学性能时&#xff0c;需要了解空气在其周围产生的流动方式。达索系统3DEXPE…

真心建议测试工程师学完Pytest框架实战,跳槽必备,学完能涨薪5k

【文章末尾给大家留下了大量的福利】 应用场景&#xff1a; pytest 框架可以解决我们多个测试脚本一起执行的问题。 它提供了测试用例的详细失败信息&#xff0c;使得开发者可以快速准确地改正问题。它兼容最新版本的 Python。它还兼容 unittest、doctest 和 nose&#xff0…

【03】Istio Gateway示例配置

3.1 开放kiali至集群外部 首先将istio-inressateway暴露集群外部; 在node02的ens33网卡上面有多余的ip地址&#xff0c;将该地址绑定在igressgateway的svc 上面。 kubectl edit svc istio-ingressgateway -n istio-system定义kiali的ingress gateway的资源配置清单 apiVersion:…

JavaEE进阶学习:Spring核心和设计思想

Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#xff0c;这就是它之所以能长久不衰的原因。Spring 支持广泛的应用场景&#xff0c;它可以让 Java 企业级…

Centos8上部署Zabbix5.0

1.关闭Selinux及防火墙&#xff0c;避免Web页面无法访问。 setenforce 0 vim /etc/selinux/config 修改“SELINUX”等号后的内容为disabled SELINUXdisabled\\关闭并关闭开机自启 systemctl stop firewalld systemctl disable firewalld 2.配置Centos8本地yum源。 mkdir /mn…

Element-Ui el-table 动态添加行

一、在项目需要使用 这个需求主要是在项目中需要用到 1.点击新增按钮&#xff0c;可以实现新增行。 2.在每个列里面可以进行输入。 3.可以删除新增的行&#xff0c;包括数据。 二、HTML代码 1.主要是循环每一个列&#xff0c;而且这些列都是动态&#xff0c;根据父组件传过来…