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

news/2024/7/24 5:59:09 标签: 算法, 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μ

双向迪杰斯特拉<a class=算法" />

基本步骤

  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 实现

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.niftyadmin.cn/n/5177481.html

相关文章

【备忘】在Nginx服务器安装SSL证书

您可以在Nginx或Tengine服务器上安装SSL证书&#xff0c;实现通过HTTPS安全访问Web服务器。本文介绍如何为Nginx或Tengine服务器安装SSL证书。 重要 本文以CentOS 8.0 64位操作系统、Nginx 1.14.2为例介绍。不同版本的操作系统或Web服务器&#xff0c;部署操作可能有所差异&a…

五、L2TPv2 VPN

L2TPv2 VPN 1、L2TPv2概述1.1.目的1.2.特点 2、L2TP原理2.1.基本概念2.2.工作原理2.2.1.协议架构2.2.2.报文结构2.2.3.报文封装2.2.4.报文传输 3、工作过程4、应用场景4.1、远程拨号用户发起L2TP隧道连接4.2、LAC接入拨号请求发起L2TP隧道连接4.3、LAC接入PPPoE用户发起L2TP隧道…

redis内存淘汰策略

当Redis已用内存超过maxmemory限定时&#xff0c;触发主动清理策略主动清理策略在Redis 4.0之前一共实现了 6 种内存淘汰策略&#xff0c;在 4.0 之后&#xff0c;又增加了 2 种策略&#xff0c;总共8种a) 针对设置了过期时间的key做处理: 1. volatile-tl;在筛选时&#xff0c;…

如何压缩前端项目中 JS 的体积

在前端项目中&#xff0c;压缩 JavaScript 文件的体积可以提高网页加载速度和性能。下面是一些常用的方法来压缩前端项目中的 JavaScript 文件体积&#xff1a; 使用压缩工具&#xff1a;使用专门的压缩工具可以自动化地压缩 JavaScript 代码。一些常用的工具包括 UglifyJS、Te…

sqli-labs关卡15(基于post提交的单引号布尔盲注)通关思路

文章目录 前言回顾上一关知识点二、靶场第十五关通关思路1、判断注入点2、猜数据库长度3、猜数据库名字4、猜表名长度5、猜表名名字6、猜列名长度7、猜列名名字8、猜数据长度9、猜数据名字 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。注…

SQL学习(CTFhub)整数型注入,字符型注入,报错注入 -----手工注入+ sqlmap注入

目录 整数型注入 手工注入 为什么要将1设置为-1呢&#xff1f; sqlmap注入 sqlmap注入步骤&#xff1a; 字符型注入 手工注入 sqlmap注入 报错注入 手工注入 sqlmap注入 整数型注入 手工注入 先输入1 接着尝试2&#xff0c;3&#xff0c;2有回显&#xff0c;而3没有回显…

策略模式-C++实现

策略模式&#xff08;Strategy&#xff09;是一种行为型设计模式&#xff0c;它允许你在运行时选择算法的行为。 策略模式有三个组件&#xff1a; 策略接口&#xff1a;定义了策略类必须实现的方法&#xff0c;它通常是以接口或者抽象类的方式存在具体策略类&#xff1a;实现…

机器人 Null impedance(零阻抗)梳理

"Null impedance"&#xff08;零阻抗&#xff09;是指机器人系统在特定情境下被设计成对外部力或运动表现出极小的阻抗。这意味着机器人系统在受到外部作用力时&#xff0c;几乎不会提供阻抗或阻力&#xff0c;使其能够灵活地适应外部环境的变化。零阻抗的设计旨在让…