Dijkstra算法与Prim算法的异同案例详解

 更新时间:2021年09月06日 09:14:58   作者:豆沙包lo  
这篇文章主要介绍了Dijkstra算法与Prim算法的异同案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

Dijkstra简述

Dijkstra算法用于构建单源点的最短路径树(MST)——即树中某个点到任何其他点的距离都是最短的。例如,构建地图应用时查找自己的坐标离某个地标的最短距离。可以用于有向图,但是不能存在负权值(Bellman-Ford可以处理负权值)。

  • 伪代码
Dijkstra() {
    for each u in G,V {
        //此处做初始化操作,给每个节点u赋键值+∞,设置空为父节点
        u.key = +∞
        u.parent = NULL
    }
    //选初始点r,Q是无向图G中所有点V的权值优先队列,key可看作源点到u的距离
    r.key = 0
    Q = G,V
    while(Q != ∅) {
          //取出Q中权值最小值的点u
          u = extractMin(Q) 
          //取点u连接的所有节点(即无向图G的邻接表中的第u个链表)
          for each v ∈ G.Adj[u] {
              if (v ∈ Q) and (w(u, v) < key) {
                  //若该节点仍在Q中且权值w(w,v)小于其原始权值,则进行松弛操作!
                  v.parent = u
                  v.key = w(u, v) + u.key
              }
          }
      }
}

Prim简述

Prim算法用于构建最小生成树——即树中所有边的权值之和最小。例如,构建电路板,使所有边的和花费最少。只能用于无向图

  • 伪代码
//无向图G, 权值w, 起始点r
MST(G, w, r) {
    for each u in G,V {
        //此处做初始化操作,给每个节点u赋键值+∞,设置空为父节点
        u.key = +∞
        u.parent = NULL
    }
    //选初始点r,Q是无向图G中所有点V的权值优先队列,key可看作u到下一个节点v的距离
    r.key = 0
    Q = G,V
    while(Q != ∅) {
          //取出Q中权值最小值的点u
          u = extractMin(Q) 
          //取点u连接的所有节点(即无向图G的邻接表中的第u个链表)
          for each v ∈ G.Adj[u] {
              if (v ∈ Q) and (w(u, v) < key) {
                  //若该节点仍在Q中且权值w(w,v)小于其原始权值,则进行松弛操作!
                  v.parent = u
                  v.key = w(u, v)
              }
          }
      }
}

MST中任意AB两点之间的距离,并不比原始图中AB的距离短,即原始图中可能存在边E(A,B)**小于**MST中的E(A,B)。

注意上述两个伪算法的差别只在于最后循环体内的松弛操作

  • 最小生成树只关心所有边的和最小,所以有v.key = w(u, v),即每个点直连其他点的最小值(最多只有两个节点之间的权值和)
  • 最短路径树只搜索权值最小,所以有v.key = w(u, v) + u.key,即每个点到其他点的最小值(最少是两个节之间的权值和)

简单总结就是,Dijkstra的松弛操作加上了到起点的距离,而Prim只有相邻节点的权值。

思想

都是使用贪婪和线性规划,每一步都是选择权值/花费最小的边。
贪婪:一个局部最有解也是全局最优解;
线性规划:主问题包含n个子问题,而且其中有重叠的子问题。

Dijkstra算法通过线性规划缓存了最优子路径的解,每一步也通过贪婪算法来选择最小的边。
Prim算法通过贪婪来选择最小的边,而Prim的每个子树都是最小生成树说明满足线性规划的两个条件。

时间复杂度

Time = θ( V * T1 + E * T2)
其中T1为取出键值最小点的时间,T2为降低键值的时间,取决于数据结构。

  • 数组
    T1= O(V), T2 = O(1), TIME = O(V * V + E) = O(V * V)
  • 二叉堆
    T1 = O(lgV), T2 = O(lgV), TIME = O(V * lgV + E * lgV) 
  • 斐波那契堆
    T1 = O(lgV), T2 = O(1), TIME = O(V * lgV + E) = O(V * lgV)

对于稀疏图来说,E远小于V*V,所以二叉堆比较好;
而对于密集图来说,E=V*V,所以数组比较好;
斐波那契堆是最好的情况。

Dijkstra特例

当边的权值都为1的时候,可以用DFS(广度优先搜索)优化时间复杂度。

  • 使用FIFO(先进先出)队列代替优先队列,优化了降低键值T2的操作为O(1)
  • 松弛操作改为
    if d[v] = +∞ {
        d[v] = d[u] + 1
        enqueue(Q, v)
    }

优化了取出键值最小点的时间T1 = O(1)

总的时间复杂度

TIME = V + E

到此这篇关于Dijkstra算法与Prim算法的异同案例详解的文章就介绍到这了,更多相关Dijkstra算法与Prim算法的异同内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ std::initializer_list 实现原理解析及遇到问题

    C++ std::initializer_list 实现原理解析及遇到问题

    这篇文章主要介绍了C++ std::initializer_list 实现原理勘误,本文通过源码解析给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • C++中线程池ThreadPool源码解析

    C++中线程池ThreadPool源码解析

    线程池(threadpool)作为五大池之一(内存池、连接池、线程池、进程池、协程池),线程池的应用非常广泛,不管事客户端程序还是后台服务端,都是提高业务处理能力的必备模块
    2022-09-09
  • 判断一个无向图是否为连通图的方法

    判断一个无向图是否为连通图的方法

    今天小编就为大家分享一篇关于判断一个无向图是否为连通图的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • C++ map与set封装实现过程讲解

    C++ map与set封装实现过程讲解

    set set是一种关联式容器,下面这篇文章主要给大家介绍了关于C++中map和set使用的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用C++具有一定的参考学习价值,需要的朋友可以参考下
    2023-03-03
  • 简单总结C语言中的运算符优先级

    简单总结C语言中的运算符优先级

    这篇文章主要介绍了C语言中的运算符优先级,文中简单总结了一些常用运算符的优先级顺序以及记忆技巧,需要的朋友可以参考下
    2016-05-05
  • C语言 模拟实现memcpy与memmove函数详解

    C语言 模拟实现memcpy与memmove函数详解

    这篇文章主要介绍了C语言详解如何模拟内存函数,用到了mencpy与memmove两个函数,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-04-04
  • kernel利用pt regs劫持seq operations的迁移过程详解

    kernel利用pt regs劫持seq operations的迁移过程详解

    这篇文章主要为大家介绍了kernel利用pt_regs劫持seq_operations进行迁移的过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • C++实现简单职工管理系统

    C++实现简单职工管理系统

    这篇文章主要为大家详细介绍了C++职工管理系统实训代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • C++容器std::vector的swap()函数使用方式

    C++容器std::vector的swap()函数使用方式

    这篇文章主要介绍了C++容器std::vector的swap()函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C++简单又轻松的讲解类和对象中友元函数

    C++简单又轻松的讲解类和对象中友元函数

    采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该类的友元函数
    2022-06-06

最新评论