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

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)

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

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

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

  2. prim算法_最小生成树(Kruskal和Prim算法)

    文章和资源同步更新至微信公众号:算法工程师之路 8月份会开启每日算法题系列,值得期待哦 上一篇文章,我们讲了图的创建和遍历,其中遍历的算法主要有BFS(广度优先算法)和DFS(深度优先算法)两种,并且 ...

  3. 图的最小生成树-Kruskal算法

    问题引入 [问题描述] 编写程序,利用带权无向图的邻接矩阵存储,实现图的最小生成树Kruskal算法. [输入形式] 输入图的顶点序列及图的边的情况.如样例所示.边的输入以输入-1,-1,-1作为结束 ...

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

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

  5. 最小生成树(Kruskal和Prim算法)

    一.先再次明确关于图的几个概念定义: 连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图. 强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称 ...

  6. Kruskal与Prim算法生成最小树

    Kruskal算法适用于边稀疏的情形 Prim算法适用于边稠密的情形 点击:Kruskal算法的理解 书上的代码: n:图G上的顶点 e:G上的边数 vest:看是否属于同一连通分量的数组,数值相等则 ...

  7. 【数据结构与算法】图结构最小生成树Kruskal算法的Java实现

    Kruskal算法 Kruskal算法是图论中用于求解最小生成树的算法,算法时间复杂度为O(eloge) 比较起Prim算法,Kruskal算法虽然同求最小生成树,却更适合稀疏网. 这里图的储存结构建 ...

  8. poj 3026 BorgMaze 最小生成树Kruskal、Prim(Prim VS报错待解决

    题意 以及 思路: 从S点有一伙人出发去消灭A点的敌人,在S点或者A点可以分裂成几个小队然后分别走,这样路径=总队路径+各个小队路径 问你怎样路径最短. 在一个y行 x列的迷宫中,有可行走的通路空格' ...

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

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

最新文章

  1. 复旦邱锡鹏团队:Transformer最新综述!
  2. pandas drop 删除行和列的方法
  3. Delphi 控制摄像头
  4. sql同时向两个表插入数据_SQL入门-数据库和客户端的安装,表的创建和数据插入...
  5. Kruskal(P)和Prim(K)算法
  6. js 字符串,数组扩展
  7. 远程桌面超出最大连接数问题
  8. C语言给考场编号,求:用C设计考场的编排,生成准考证号基本要求:br/(1)用 爱问知识人...
  9. cdev_init函数
  10. 命名实体识别实践 - CRF
  11. 最长回文子串(Longest Palindromic Substring)——三种时间复杂度的解法及LeetCode[5] - 最长回文子串动态规划
  12. coreldraw x7对齐快捷键_CDR基础CorelDraw X7中文版快捷键大全
  13. Adobe After Effects(AE)2022软件安装[MAC]
  14. 如何将自己的电脑做成服务器
  15. UESTC 1634 去年春恨却来时,落花人独立,微雨燕双飞
  16. 程序员一年多少行_程序员版的倚天屠龙,看完泪奔!
  17. Eidetic:助你提升记忆力的酷应用
  18. bugku~图穷匕见
  19. Tools/Profiler
  20. java 电子时钟_java多线程编程制作电子时钟

热门文章

  1. hive hql文档_大数据学习不能停,看看如何安装hive快800倍!共572.91M视频文档
  2. GP学习(三)—How to run a geoprocessing tool
  3. python中的异或操作_Python中的异或和位操作的反转
  4. json vue 对象转数组_vue.js基于v-for实现批量渲染 Json数组对象列表数据示例
  5. strus2拦截器中获取客户端ip
  6. c++ string 回文串_第33期:上海自来水来自海上,回文字符串验证!
  7. python根据TF-IDF使用sklearn(TfidfVectorizer)计算句子的embedding
  8. 华为p20支持手机云闪付吗_余承东:明年华为智能手机全面支持鸿蒙系统
  9. aspnetcore的中间件
  10. iview表格嵌套Tooltip