假期里面系统地研究了一下最小生成树,下面就跟大家分享一下心得。最小生成树(Minimum Spanning Tree, MST)是图论的一个分支,主要用于从一个包含n个结点的连通图中提取出一个包含全部n个结点的最小连通子图。《算法导论》中给出的术语表示是:对于无向连通图G=(V,E),其中V是顶点集合,E是连接各个顶点的边的集合。对图中每一条边(u,v)∈E,都有一个权值w(u,v)表示连接u和v的代价。我们希望找出一个无回路的子集T#8838;E,它连接了所有的顶点,其权值之和w(T)=∑w(u,v)为最小。

解决最小生成树问题有两种主流的算法,分别称作普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。不过,究竟何时用哪一种算法令很多人纠结,本文就来详细探讨这一问题。

先来说说两种算法的共同点,易知n个顶点的无向连通图最小生成树一定由全部顶点及(n-1)条边组成,而寻找这些顶点和边的过程是一种贪心策略:维护一个最小生成树子集A,使得每次都将G中的一条边加入A中,直到A满足最小生成树的条件为止。就Prim算法而言,每次加入A中的是(G-A)与A中具有最小权值相连接的那条边(相当于把顶点按(G-A)与A分为两个阵营);而对于Kruskal算法,每次加入A中的是(G-A)中具有最小权值且两个顶点在A中互不可达的边。换句话说,Prim算法每次选择是基于顶点的,而Kruskal算法每次选择是基于边的。

具体说来,Prim算法的基本思想是:从任意的顶点开始,构造所求的最小生成树子集A;每次都以(G-A)中的顶点为对象,找到(G-A) 与A中顶点对所形成的边的权值最小者,将该条边加入A中,直到A中包含了所有的顶点为止。Prim算法的时间复杂度取决于实现A的数据结构,如果采用基于二叉堆的优先队列来实现的话,那么得到最小关键字、添加删除元素都可以在logV时间内来完成,外围循环的次数是(V-1),不过每次更新权值是对图的邻接表进行扫描,整体的复杂度是O(E),考虑到V<=E 1,因此整个Prim算法的时间复杂度为O(ElogV)。

Kruskal算法的基本思想是:首先对所有的边的权值进行从小到大排序,然后开始构造所求的最小生成树子集A;每次都以(G-A)中的边为对象,根据之前的排序结果找到(G-A) 中权值最小且两顶点在A中互不可达的边,将该条边加入A中,直到A中包含了(n-1)条边为止。Kruskal算法的时间复杂度取决于实现A的数据结构及排序算法。如果采用快速排序加并查集来实现的话,排序的时间复杂度为O(ElogE) ,创建集合的时间复杂度为O(V),元素查找及集合合并的时间复杂度为O(E),仍然考虑到V-1<=E

可以看出,从渐近的角度来说,两种算法的时间复杂度是相同的。不过,根据我对实践中的观察和总结,80%以上的最小生成树问题都是用Prim算法解决的。其实这一现象是有一定原因的。首先,虽说渐近意义上两种算法的计算时间相同,但实际操作中,Prim算法要更快一些。这是因为Kruskal算法单单排序一项就要用掉O(ElogE)的时间,而这个时间几乎相当于Prim算法耗时的全部(如果Prim算法采用合适的数据结构来实现的话)。即便是快速排序,也仅仅是平均意义上的O(ElogE),某些数据依然可能使时间复杂度退化为O(E^2)。这一点对于稠密图尤其不利,因为待排序的边数太多,往往严重拖慢程序的运行,而我们甚至还没考虑对并查集操作的时间。其次,Kruskal算法的空间开销往往较大。如果顶点数V>1500,对于稠密图,维护一个长度为E≈V^2/2=10^6的边权值数组可能就会让系统无法负荷,另外我们还没考虑并查集这个长度为V的数组;而Prim算法无需对边操作,只要两个长度为V的数组存储父亲结点及最小权值就行了。这种空间复杂度的差异往往使得解决问题的人在面对顶点数较多的稠密图时除了Prim算法外别无选择。最后,Prim算法是基于顶点的,每次循环结束得到的也是一个最小生成树,是对于已经加入到集合A中的结点而言的最小生成树。这种满足子问题解决方案的性质在某些情况下很有优势。而Kruskal算法是基于边的,每次循环结束后得到的是一个最小生成子森林,这种结构对于解决类似问题的用处要比Prim算法中的子问题差很多,因此这方面Kruskal算法也是逊色的。

上面我们多次提到稠密图,这样是不是局限了问题的范围呢?实际上还真不是。图这种数据结构在现实应用中的实例包括网络布局、城市规划等,这些实例中的图往往都是稠密图,稀疏图少之又少;试想一下,V个结点形成的图边的个数往往与V^2数量级相同,如果边数很少一般有一些结点就是多余的,因此实际使用中我们大多数用的就是稠密图,我们做的假设没有问题。那么,是不是Kruskal算法就真的无用武之地呢?也不一定,看看下面的问题。

问题:现在要为N个村庄铺路,使得任意两个村庄之间可以互相到达(可间接到达),现在某些村庄之间已经铺好了道路,问如何将剩余的道路铺好使得最终全部道路的长度最短?

对于这个问题,不经思索就想使用Prim算法是鲁莽的,例如截取Prim算法中循环的部分:题目中有些边已经被选进A中,那么就沿着Prim算法中的N-1次循环继续下去,直到所有顶点都在A中。可是,这种算法忽略了一个问题:Prim算法每次循环后A中都是一颗树,可是该算法能满足要求吗?实际上从算法的一开始就不能满足,因为铺好的那些路不一定形成一棵树,很可能是森林!另外即便是树也不一定是真正的最小生成树的子集;这个问题本身是最小生成树的变形,其实现方式已经沿着Kruskal算法的思想了,因此我们不得不继续做下去,即针对所有的边进行排序,每次选取权值最小且不属于已经修好的路段且两顶点在A中互不可达的边,然后直到(N-1)条边被选入A中为止,这才是正确的算法。

看来,Kruskal算法在某些情况也是有其作用的,不过这种特例情况还是很少,只要做出细致的分析一般都能鉴别出来。作为本文的结语,笔者针对最小生成树使用哪种算法提出几点建议:

1.对于顶点数较多的图,建议考虑Prim算法,慎用Kruskal算法,因为后者可能会造成内存溢出;

2.对于稠密图,建议考虑Prim算法,慎用Kruskal算法,因为后者可能消耗更多的时间;

3.对于最小生成树问题的变形,建议仔细分析,看其基本是向哪种算法的方向倾斜,然后考虑采用那种方法的可行性。

转载于:https://blog.51cto.com/linxueyi324/990882

最小生成树的纠结_交流电之王-ChinaUnix博客相关推荐

  1. Git 存储过程探究_无赖皮肤-ChinaUnix博客

    1一些基础概念 1.1SHA1 SHA1是密码学上的一种算法,git通过它来识别文件.在git中,通过对"对象"进行计算得来的SHA1,来得到对该文件项目的索引.其中SHA1值是一 ...

  2. ubuntu18.04在终端安装pip3时404 Not Found [IP: 91.189.91.24 80]_木绿的博客-CSDN博客

    ubuntu18.04在终端安装pip3时404 Not Found [IP: 91.189.91.24 80]_木绿的博客-CSDN博客 解决办法如下 亲测可用 sudo apt-get updat ...

  3. 手把手教你用Keras进行多标签分类(附代码)_数据派THU-CSDN博客 (翻译:程思衍校对:付宇帅)

    手把手教你用Keras进行多标签分类(附代码)_数据派THU-CSDN博客 手把手教你用Keras进行多标签分类(附代码)_数据派THU-CSDN博客

  4. shaderToy初学笔记(一)(​转载自最简单的ShaderToy入门 - 笑脸渲染_亨利王的博客-CSDN博客_shadertoy)

    void mainImage( out vec4 fragColor, in vec2 fragCoord ) {vec2 uv = fragCoord/iResolution.xy;uv-=.5;f ...

  5. 使用Windows live Writer 2012发布ChinaUnix博客

    最近打算把博客相应的文章发布到ChinaUnix上,找了很多的文章终于找到如何发表,记录如下. 有关windows live writer的安装可以参考,我另外一篇文章.<烂泥:用Windows ...

  6. 限制会话id服务端不共享_会话控制 - able-woman - 博客园

    会话控制是什么? cookie和session都是跟踪整个会话过程的技术手段.而会话,就是用户通过浏览器和服务器的一次通话. 为什么要有会话控制? 因为HTTP协议是无状态的,服务器不知道用户上一次做 ...

  7. python3基础教程雪峰_[雪峰磁针石博客]python3快速入门教程2数据结构1变量与赋值...

    Published: 日 02 九月 2018 语法基础 解释器像简单的计算器:可以输入表达式,它会返回值.表达式语法很简单:运算符 + , - , * 和 / 与其它语言一样(例如Pascal或C) ...

  8. 解读java面试_解读王垠博客“一道 Java 面试题”

    偶然拜读IT界知名大佬王垠老师的博客,发现一个有意思的题目: 1 //这段代码里面到底哪一行错了?为什么?2 //原文:http://www.yinwang.org/blog-cn/2020/02/1 ...

  9. java 异想_异想家博客图片批量压缩程序

    为了方便给自己的博客配图,用Golang写了一个脚本处理,现分享出来,有需要的朋友也可以参考修改使用. 压缩规则 1.图片都等比例压缩,不破坏长宽比. 2.如果是横屏图片,压缩到宽度为1280,高度适 ...

最新文章

  1. 最热开源无服务器函数:五大Fission架构参考
  2. The advantages of SMRT sequencing
  3. 把学生类按单科成绩排序_重庆新高考几个核心点:分数线种类、96个志愿、投档排序规则...
  4. Hadoop集群启动时NameNode未启动解决方法
  5. 了解一下JAVA中的NIO模块
  6. 一个汉字在数据库占几个字节
  7. 大神干货:腾讯广告算法大赛亚军女极客生存图鉴
  8. 老程序员提给后浪程序员的职涯建议
  9. 金山安全联手方正科技 为用户提供最佳互联网安全环境
  10. 如何时刻保持在目标的正确轨道上
  11. 1千条数据平均分配给15人_母狗一胎生下15只小狗,差点破纪录,1年后再相聚的场景让人泪目...
  12. QT等待动态图gif加载透明背景lable
  13. excel选择符合条件的行
  14. 为什么平方损失函数不适应于分类问题?——从概率论的角度
  15. 第一章 ArcGIS初识
  16. python爬取晋江文学城_晋江文学城[本站宗旨]
  17. mmdetection(2): DeformableConvNets(DCN)
  18. 一个屌丝程序猿的人生(十五)
  19. hadoop hdfs合并文件下载到本地单个文件
  20. 利用开放的isbn查询Api接口录入图书信息,工作效率倍增

热门文章

  1. win11beta版如何升级正式版 Windows11beta升级正式版的步骤方法
  2. 利用ros3d.js实现 turtlebot3 在web 端显示并导航
  3. fmt标签实现时间日期格式化,与类型转换Converter
  4. ppt转html5 带动画_这组PPT设计,真的太漂亮了!
  5. python怎么训练模型_GPU如何训练大批量模型?方法在这里
  6. libpython3.7m so静态库_libpython3.7m.dll
  7. ❤️Mybatis开发中什么是多对一处理、一对多处理?
  8. 利用函数求两个数的最大值
  9. debian之快速截图
  10. php 系统找不到指定的路径.,PHP网站(windows2003服务器 IIS6)提示:系统找不到指定的路径。...