文章和资源同步更新至微信公众号:算法工程师之路

8月份会开启每日算法题系列,值得期待哦

上一篇文章,我们讲了图的创建和遍历,其中遍历的算法主要有BFS(广度优先算法)和DFS(深度优先算法)两种,并且DFS算法对很多问题都有很好的启示!而今天我们要说一个非常实用的算法——最小生成树的建立!这是图论中一个经典问题,可以使用Kruskal和Prim两种算法来进行实现!

MST

什么是最小生成树

在给定一张无向图,如果在它的子图中,任意两个顶点都是互相连通,并且是一个树结构,那么这棵树叫做生成树。当连接顶点之间的图有权重时,权重之和最小的树结构为最小生成树!

在实际中,这种算法的应用非常广泛,比如我们需要在n个城市铺设电缆,则需要n-1条通信线路,那么我们如何铺设可以使得电缆最短呢?最小生成树就是为了解决这个问题而诞生的!

最小生成树

如上图所示,一幅两两相连的图中,找到一个子图,连接到所有的节点,并且连接边的权重最小(也就是说边的数量也是最小的,这也保证了其是树结构).

Kruskal算法(克鲁斯卡算法)

Kruskal算法是一种贪心算法,我们将图中的每个edge按照权重大小进行排序,每次从边集中取出权重最小且两个顶点都不在同一个集合的边加入生成树中!注意:如果这两个顶点都在同一集合内,说明已经通过其他边相连,因此如果将这个边添加到生成树中,那么就会形成环!这样反复做,直到所有的节点都连接成功!

Kruskal算法流程

在这个算法中,最重要的一环就是判断两个节点在不在同一个集合内,很多人想,那你直接用一个set来保存不就好了?这是思路显然不行,因为假设A和其他三个节点相连,同属一个集合,而B和另外三个节点相连,同属一个集合,那么我们将A和B取并集时,是将这两组数据合并一起的,如果使用set,那么当数据量大时还需要遍历,复杂度就会很高,因此使用并查集就会效率快很多了

  1. 对所有节点遍历建立并查集,按照边的权重建立最小堆
  2. 取出最小堆堆顶数据,并判断两端节点是否在同一集合
  3. 如不在,则将这两个节点添加到同一集合,接着将边加入生成边,如在,则不进行操作,为无效边
  4. 重复上面的操作,直到所有的边都检查完
unordered_set kruskalMST(Graph graph){ auto cmp = [](const Edge& a, const Edge& b){ return a.weight > b.weight; // 最小堆 }; vector list; for(auto ite: graph.nodes){ list.push_back(ite.second); } UnionFindSet unionFind(list); // 建立并查集 priority_queue, decltype(cmp)> smallQueue(cmp); for(auto edge: graph.edges){ smallQueue.push(*edge); } // 构造选中的输出边集 unordered_set result; while(!smallQueue.empty()){ Edge edge = smallQueue.top(); smallQueue.pop(); if(!unionFind.isSameSet(edge.from, edge.to)){ // 判断是否为一个环,如果一个边的两端节点为一个集合,那么必为一个闭合环 result.insert(edge); unionFind.Union(edge.from, edge.to); } } return result;}

Prim算法(普里姆算法)

Prim算法是另一种贪心算法,和Kuskral算法的贪心策略不同,Kuskral算法主要对边进行操作,而Prim算法则是对节点进行操作,每次遍历添加一个点,这时候我们就不需要使用并查集了。具体步骤为:

Prim算法流程

  1. 建立边set用来存放结果,建立节点set用来存放节点同时用于标记是否被访问过,建立边的最小堆
  2. 开始遍历所有节点,如果没有访问,则添加到节点set,然后将其相连的边入堆。
  3. 从堆中取最小的边,然后判断to节点是否被访问过,如果没有,将这个边加入生成树(我们想要的边),并标记该节点访问。
  4. 然后将to节点所相连的边添加到最小堆中,不然这个网络就不会向外扩展了(这个步骤是必须的)。
  5. 循环上面的操作,直到所有的节点遍历完。

注意:对于单连通,从一个节点出发就可以直接找到完整的最小生成树,因此最外的for循环也可以为一个顺序结构,但多连通,就需要从不同的节点出发了!!!

unordered_set primMST(Graph graph){ // 装边的最小堆 auto cmp = [](const Edge& e1, const Edge& e2){ return e1.weight > e2.weight; }; priority_queue, decltype(cmp)> smallQueue(cmp); // 判断节点是否访问过 unordered_set node_set; unordered_set result; for(auto ite: graph.nodes){ if(node_set.find(*ite.second) == node_set.end()){ // 如果没有访问,将其标记为访问过,并把它对应的边放入最小堆 node_set.insert(*ite.second); for(Edge* edge: ite.second->edges){ smallQueue.push(*edge); } // 在当前这个图中寻找最小生成树 while(!smallQueue.empty()){ // 从堆中取出一个最小权重边,并取出对应节点 Edge help_edge = smallQueue.top(); smallQueue.pop(); Node edge_to = *(help_edge.to); // 然后判断这个节点是否被访问过,如果没有则将这个边加入边集 if(node_set.find(edge_to) == node_set.end()){ result.insert(help_edge); node_set.insert(edge_to); // 标记edge_to也已经访问过了 for(Edge *newEdge: edge_to.edges){ smallQueue.push(*newEdge); } } } } } return result;}

那么对于这两种算法,我们应该用哪种呢?记得某个人说过这句话,算法没有优劣,每个算法都有它的使用场景,在对的场合使用对的算法,这才是算法工程师应该做的事情!

由于Kruksal算法是对边进行操作,先取出边,然后判断边的两个节点,这样的话,如果一个图结构非常的稠密,那么Kruksal算法就比较慢了,而Prim算法只是对节点进行遍历,并使用set进行标记,因此会相对于Kruksal算法,在稠密图方面好很多,因此Kruksal算法常用于稀疏图,而Prim算法常用于稠密图!

资源分享

以上完整代码文件(C++版),文件名为:最小生成树(Kruskal和Prim算法),请关注我的个人公众号 (算法工程师之路),回复"左神算法基础CPP"即可获得,并实时更新!希望大家多多支持哦~

公众号简介:分享算法工程师必备技能,谈谈那些有深度有意思的算法,主要范围:C++数据结构与算法/深度学习(CV),立志成为Offer收割机!坚持分享算法题目和解题思路(Day By Day)

prim算法_最小生成树(Kruskal和Prim算法)相关推荐

  1. 【老生谈算法】matlab实现Kruskal避圈算法求最小生成树——Kruskal避圈算法

    基于MATLAB的Kruskal避圈算法求最小生成树 1.原文下载: 本算法原文如下,有需要的朋友可以点击进行下载 序号 原文(点击下载) 本项目原文 [老生谈算法]基于MATLAB的Kruskal避 ...

  2. 最小生成树 Kruskal 和 Prim算法及堆优化

    目录 生成树/最小生成树是什么. 一.Kruskal算法 Kruskal模板 二.Prim算法及堆优化 1.遍历 Prim 普通模板 2.堆优化 Prim 堆优化模板 解决最小生成树的问题之前,我们先 ...

  3. prim算法_求解最优树——Prim算法与Kruskal算法

    本文主要参考: 1.<Matlab数学建模算法全收录(数学建模比赛必备参考资料).pdf> 2.最小生成树-Prim算法和Kruskal算法 1 前言 简单来说,图由顶(就是结点)和边构成 ...

  4. 最小生成树 算法_最小生成树算法

    最小生成树 算法 距离我的资格考试只有十天的路程,我决定离开教科书,改回写作. 毕竟,如果我可以解释这些概念,那么我应该能够通过对它们的测试,对吗? 好吧,今天我很有趣地介绍了算法课程中的一个概念:最 ...

  5. k均值算法 二分k均值算法_如何获得K均值算法面试问题

    k均值算法 二分k均值算法 数据科学访谈 (Data Science Interviews) KMeans is one of the most common and important cluste ...

  6. java常见的hash算法_常见的哈希算法和用途

    写在前面 哈希算法经常会被用到,比如我们Go里面的map,Java的HashMap,目前最流行的缓存Redis都大量用到了哈希算法.它们支持把很多类型的数据进行哈希计算,我们实际使用的时候并不用考虑哈 ...

  7. 最小径集的算法_机器学习的利器——集成算法

    最近在打算法竞赛的时候用到了集成算法,效果还不错,索性就总结了一篇集成算法的文章,希望能帮到正在转行的数据分析师们. 集成算法核心思想 集成算法的核心思想是通过构建并结合多个学习器来完成学习任务,也就 ...

  8. 标签传播算法_复杂网络社区发现算法汇总

    社区发现 这篇文章汇总了一些常见的社区发现概念和算法,包括 Modularity Q Fast Unfolding(Louvain Algorithm) LPA SLPA KL算法 GN算法 社区: ...

  9. 图像重建算法_基于深度学习图像重建算法(DLIR)对CT图像质量和剂量优化的研究:体模实验...

    编者按:今年Joël Greffier博士等在European Radiology (IF 4.1)上发表了题为<Image quality and dose reduction opportu ...

最新文章

  1. 软件安全性能測试(转载)
  2. Xor Path - 牛客
  3. [題解](最小生成樹)luogu_P2916安慰奶牛
  4. OpenCASCADE绘制测试线束:图形命令之AIS 查看器——查看命令
  5. Sublime Text 3下Emmet使用技巧
  6. LINUN 网络连接小记
  7. oracle 安装ora 27102,ORA-27102 解决办法
  8. dragloader.js帮助你在页面原生滚动下实现Pull Request操作
  9. 改行了 写一篇 PLC 相关的 西门子 S7 300/400 控制器
  10. python3 super_Python super()– Python 3 super()
  11. python的三种取整方式_python3.6 numpy 数组的多种取整方式
  12. 自己动手源码包制作rpm 包 (二)
  13. 【数字信号去噪】基于matlab小波软阈值+硬阈值+改进的阈值高斯脉冲信号去噪【含Matlab源码 1706期】
  14. 两种土壤类型数据的简介、下载教程
  15. win10 -- 增加新建 TXT 文档快捷键
  16. 【JSD2209-DAY02】数据基本类型
  17. 文件传输协议:FTP和TFTP
  18. 【山东农大】“我与学霸面对面”报告会暨社团全体新成员大会成功举办
  19. c语言中字符 a b =,C语言中(ab)?a:b和(ab)?b:a有什么区别,C语言中,a++ +b和a+ ++b有什么不同...
  20. 计算机组成原理课后习题

热门文章

  1. 在cdh5.1.3中在mapreduce使用hbase
  2. With(ReadPast)就不会被阻塞吗?
  3. 转载--SQL还原数据库后孤立用户问题处理(SQL 数据库 拥有对象 无法删除)
  4. Single sign-on,什么是单点登陆?
  5. 《我也能做CTO之程序员职业规划》推荐序
  6. php设计要求,《PHP设计模式介绍》第十章 规范模式
  7. java 字符串转日历_将字符串转换为Java中的日历对象
  8. SqlServer两表之间:根据一个表的字段更新另一个表的字段
  9. 一文了解H5照片上传过程
  10. CentOS 特殊变量($0、$1、$2、 $?、 $# 、$@、 $*)