数据结构:最小生成树的普里姆算法和克鲁斯卡尔算法

对于一个带权(假设每条边上的权均为大于零的实数)连通无向图 G 中的不同生成树,其每棵树的所有边上的权值之和也可能不同;图的所有生成树中具有边上的权值之和最小的树称为图的最小生成树(Minimal Spanning Tree)。

按照生成树的定义, n n n 个顶点的连通图的生成树有 n n n 个顶点、 ( n − 1 ) (n-1) (n1) 条边。因此,构造最小生成树的准则有以下 3 条:

  1. 必须只使用该图中的边来构造最小生成树;
  2. 必须使用且仅使用 ( n − 1 ) (n-1) (n1) 条边来连接图中的 n n n 个顶点;
  3. 不能使用产生回路的边。

构造最小生成树有多种算法,其中多数算法利用了最小生成树的下列一种简称为 MST 的性质:假设 N = ( V , E ) N=(V,E) N=(V,E) 是一个连通网(带权连通图), U U U 是顶点集 V V V 的一个非空子集。若 ( u , v ) (u,v) (u,v) 是一条具有最小权值(代价)的边,其中 $ u\in U,~v\in V-U$ ,则必存在一棵包含边 ( u , v ) (u,v) (u,v) 的最小生成树。

这个结论的证明,此处从略,可以参考《数据结构》(严蔚敏,人民邮电出版社)。

求图的最小生成树有很多实际应用,例如城市之间的交通工程造价最优问题就是一个最小生成树问题。求图的最小生成树有两个算法著名的算法:普里姆算法和克鲁斯卡尔算法。

普里姆算法

普里姆算法的构造过程

普里姆(Prim)算法是一种构造最小生成树的算法。

假设 G = ( V , E ) G=(V,E) G=(V,E) 是一个具有 n n n 个顶点的带权连通图, T = ( U , T E ) T=(U,TE) T=(U,TE) G G G 的最小生成树,其中 U U U T T T 的顶点集, T E TE TE T T T 的边集,则由 G G G 构造从起始点 v v v 出发的最小生成树 T T T 的步骤如下:

  1. 初始化 U = { v } U=\{v\} U={v} ,以 v v v 到其他顶点的所有边为候选边。
  2. 重复以下步骤 ( n − 1 ) (n-1) (n1) 次,使得其他 ( n − 1 ) (n-1) (n1) 个顶点被加入到 U U U 中。
    • 从候选边中挑选权值最小的边加入 T E TE TE ,设该边在 V − U V-U VU 中的顶点是 k k k ,将 k k k 加入 U U U 中;
    • 考査当前 V − U V-U VU 中的所有顶点 j j j ,修改候选边,若 ( k , i ) (k,i) (k,i) 的权值小于原来和顶点 j j j 关联的候选边,则用 ( k , i ) (k,i) (k,i) 取代后者作为候选边。

例如,对于图 8.4.7 所示带权连通图,假设起始点为顶点 0,采用普里姆算法构造最小生成树。

在这里插入图片描述

图 8.4.7 带权连通图
  1. 最小生成树 T T T 包含所有顶点。
  2. U = { 0 } , V − U = { 1 , 2 , 3 , 4 , 5 , 6 } U=\{0\},~V-U=\{1,2,3,4,5,6\} U={0}, VU={1,2,3,4,5,6} ,在这两个顶点集之间选择第 1 条最小边 ( 0 , 5 ) (0,5) (0,5) 添加到 T E TE TE 中,即 T E = { ( 0 , 5 ) } TE=\{(0,5)\} TE={(0,5)}
  3. U = { 0 , 5 } , V − U = { 1 , 2 , 3 , 4 , 6 } U=\{0,5\},~V-U=\{1,2,3,4,6\} U={0,5}, VU={1,2,3,4,6} ,在这两个顶点集之间选择第 2 条最小边 ( 5 , 4 ) (5,4) (5,4) 添加到 T E TE TE 中,即 T E = { ( 0 , 5 ) , ( 5 , 4 ) } TE=\{(0,5),(5,4)\} TE={(0,5),(5,4)}
  4. U = { 0 , 5 , 4 } , V − U = { 1 , 2 , 3 , 6 } U=\{0,5,4\},~V-U=\{1,2,3,6\} U={0,5,4}, VU={1,2,3,6}​ ,在这两个顶点集之间选择第 3 条最小边 ( 4 , 3 ) (4,3) (4,3)​ 添加到 T E TE TE​ 中,即 T E = { ( 0 , 5 ) , ( 5 , 4 ) , ( 4 , 3 ) } TE=\{(0,5),(5,4),(4,3)\} TE={(0,5),(5,4),(4,3)}​。
  5. U = { 0 , 5 , 4 , 3 } , V − U = { 1 , 2 , 6 } U=\{0,5,4,3\},~V-U=\{1,2,6\} U={0,5,4,3}, VU={1,2,6}​ ,在这两个顶点集之间选择第 4 条最小边 ( 3 , 2 ) (3,2) (3,2)​ 添加到 T E TE TE​ 中,即 T E = { ( 0 , 5 ) , ( 5 , 4 ) , ( 4 , 3 ) , ( 3 , 2 ) } TE=\{(0,5),(5,4),(4,3),(3,2)\} TE={(0,5),(5,4),(4,3),(3,2)}​。
  6. U = { 0 , 5 , 4 , 3 , 2 } , V − U = { 1 , 6 } U=\{0,5,4,3,2\},~V-U=\{1,6\} U={0,5,4,3,2}, VU={1,6}​ ,在这两个顶点集之间选择第 5 条最小边 ( 2 , 1 ) (2,1) (2,1)​ 添加到 T E TE TE​ 中,即 T E = { ( 0 , 5 ) , ( 5 , 4 ) , ( 4 , 3 ) , ( 3 , 2 ) , ( 2 , 1 ) } TE=\{(0,5),(5,4),(4,3),(3,2),(2,1)\} TE={(0,5),(5,4),(4,3),(3,2),(2,1)}​。
  7. U = { 0 , 5 , 4 , 3 , 2 , 1 } , V − U = { 6 } U=\{0,5,4,3,2,1\},~V-U=\{6\} U={0,5,4,3,2,1}, VU={6} ,在这两个顶点集之间选择第 6 条最小边 ( 1 , 6 ) (1,6) (1,6) 添加到 T E TE TE 中,即 T E = { ( 0 , 5 ) , ( 5 , 4 ) , ( 4 , 3 ) , ( 3 , 2 ) , ( 2 , 1 ) , ( 1 , 6 ) } TE=\{(0,5),(5,4),(4,3),(3,2),(2,1),(1,6)\} TE={(0,5),(5,4),(4,3),(3,2),(2,1),(1,6)},即得到了最小生成树,如图 8.4.8 所示。

在这里插入图片描述

图 8.4.8 由普里姆算法得到的最小生成树

如果每次选择最小边时,存在多条同样权值的边可选,则任选其一即可。

克鲁斯卡尔算法

克鲁斯卡尔(Kruskal)算法是一种按权值的递增次序选择合适的边来构造最小生成树的方法。

克鲁斯卡尔算法的构造过程

假设 G = ( V , E ) G=(V,E) G=(V,E) 是一个具有 n n n 个顶点的带权连通无向图, T = ( U , T E ) T=(U,TE) T=(U,TE) G G G 的最小生成树,则构造最小生成树的步骤如下:

  1. U U U 的初值为 V V V (即包含有 G G G 中的全部顶点), T E TE TE 的初值为空集(即图 T T T 中的每一个顶点都构成一个分量)。
  2. 将图 G G G 中的边按权值从小到大的顺序依次选取,若选取的边未使生成树 T T T 形成回路,则加入 T E TE TE ,否则舍弃,直到 T E TE TE 中包含 ( n − 1 ) (n-1) (n1) 条边为止。

以图 8.4.7 所示的带权连通图为例,采用克鲁斯卡尔算法构造最小生成树,其过程如下:

  1. 将所有边按权值递增排序:(0,5), (2,3), (1,6), (1,2), (3,6), (3,4), (4,6), (4,5), (0,1)

  2. 最小生成树 T T T 包含所有顶点。

  3. 选最小的边 (0,5) 加入到 T T T 中,此时不会出现回路。

  4. 选第 2 小的边 (2,3) 加入到 T T T 中,此时不出现回路。

  5. 选第 3 小的边 (1,6) 加入到 T T T 中,此时不出现回路。

  6. 选第 4 小的边 (1,2) 加入到 T T T​ 中,此时不出现回路。

  7. 选第 5 小的边 (3,6) 加入到 T T T 中,此时出现回路,故舍弃它。选第 6 小的边 (3,4) 加入到 T T T 中,此时不出现回路。

  8. 选第 7 小的边 (4,6) 加入到 T T T 中,此时出现回路,故舍弃它。选第 8 小的边 (4,5) 加入到 T T T​ 中,此时不出现回路。

    至此在 T T T 中已经有 6 条边( n = 7 n=7 n=7),产生了最小生成树,如图 8.4.9 所示。

    在这里插入图片描述

    图 8.4.9 由克鲁斯卡尔算法得到的最小生成树

将这里用克鲁斯卡尔算法所得到的最小生成树,与上一节中用普里姆算法得到的最小生成树对比,可以发现,二者结果相同。这在本例中是一个巧合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901655.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Information-Theoretic Limits of Bistatic Integrated Sensing and Communication

摘要 双静态感知指的是发射器(照亮目标)和感知接收器(估计目标状态)在物理上分离的场景,这与发射和感知功能共存的单静态感知形成对比。在实际场景中,双静态感知可能需要应对系统约束,或者作为…

XCTF-web(四)

unserialize3 需要反序列化一下:O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;} php_rce 题目提示rce漏洞,测试一下:?s/Index/\think\app/invokefunction&functioncall_user_func_array&vars[0]phpinfo&vars[1][]1 flag&#xff1…

Java Stream深度解析 高阶技巧与性能优化实战

文章目录 一、Stream底层机制揭秘1.1 Stream流水线架构1.2 Spliterator探秘 二、自定义收集器高级实现2.1 实现高性能统计收集器2.2 多级分组优化技巧 三、并行流深度优化3.1 并行度控制策略3.2 工作窃取(Work-Stealing)优化 四、无限流与短路操作4.1 生成无限质数流4.2 短路操…

TailwindCss快速上手

什么是Tailwind Css? 一个实用优先的 CSS 框架,可以直接在标记中组合以构建任何设计。 开始使用Tailwind Css 如何安装 下面是使用vite构建工具的方法 ①安装 Tailwind CSS: tailwindcss通过tailwindcss/vitenpm安装。 npm install tailwindcss tailwindcss…

Web前端 (CSS篇)

什么是CSS? css(Cascading Style Sheets)是层叠样式表或级联样式表,是一组设置规则,用于控制web页面外观。 为什么使用CSS? CSS 用于定义网页的样式,包括针对不同设备和屏幕尺寸的设计和布局。 CSS 实例 body {background-col…

微服务2--服务治理与服务调用

前言 :本文主要阐述微服务架构中的服务治理,以及Nacos环境搭建、服务注册、服务调用,负载均衡以及Feign实现服务调用。 服务治理 服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现。 服务注册:在…

智能麻将出牌组件

开篇引言​ 麻将作为一款风靡全球的策略性游戏,其复杂的规则和多变的牌局给玩家带来了无尽乐趣。在数字化时代,运用编程技术为麻将游戏赋予智能,实现自动出牌功能,不仅能提升玩家体验,还能深入探索算法在博弈游戏中的…

“大湾区珠宝艺境花园”璀璨绽放第五届消博会

2025年4月13日,第五届中国国际消费品博览会(以下简称"消博会")重要主题活动——《大湾区珠宝艺境花园》启动仪式在海南国际会展中心2号馆隆重举行。由广东省金银珠宝玉器业厂商会组织带领粤港澳大湾区优秀珠宝品牌,以“…

基于前端技术的QR码API开发实战:从原理到部署

前言 QR码(Quick Response Code)是一种二维码,于1994年开发。它能快速存储和识别数据,包含黑白方块图案,常用于扫描获取信息。QR码具有高容错性和快速读取的优点,广泛应用于广告、支付、物流等领域。通过扫…

利用耦合有限元和神经网络计算的骨重塑模拟多尺度方法

Multiscale methodology for bone remodelling simulation using coupled finite element and neural network computation 摘要:本文旨在开发一种基于有限元分析(FEA)和神经网络(NN)计算的多尺度分层混合模型&#xf…

使用异步特征引发的错误error[E0195]: lifetime parameters or bounds on method `before_save`

问题描述&#xff1a; 使用SeaOrm保存实体到数据库时不想每次都设置更新时间&#xff0c;所以想通过实现ActiveModelBehavior在保存实体前统一设置更新时间 impl ActiveModelBehavior for ActiveModel {async fn before_save<C>(self, _db: &C, _insert: bool) -&…

TVS管与ESD保护二极管详解:原理、区别与应用选型

一、TVS管&#xff08;瞬态电压抑制二极管&#xff09; 1. 基本定义 TVS管&#xff08;Transient Voltage Suppressor&#xff09; 是一种用于抑制瞬态高压脉冲的半导体器件&#xff0c;通过雪崩击穿效应快速钳位电压&#xff0c;保护后端电路。 2. 核心特性参数 参数定义公…

Day08 【基于jieba分词实现词嵌入的文本多分类】

基于jieba分词的文本多分类 目标数据准备参数配置数据处理模型构建主程序测试与评估测试结果 目标 本文基于给定的词表&#xff0c;将输入的文本基于jieba分词分割为若干个词&#xff0c;然后将词基于词表进行初步编码&#xff0c;之后经过网络层&#xff0c;输出在已知类别标…

入门-C编程基础部分:6、常量

飞书文档https://x509p6c8to.feishu.cn/wiki/MnkLwEozRidtw6kyeW9cwClbnAg C 常量 常量是固定值&#xff0c;在程序执行期间不会改变&#xff0c;可以让我们编程更加规范。 常量可以是任何的基本数据类型&#xff0c;比如整数常量、浮点常量、字符常量&#xff0c;或字符串字…

第二阶段:数据结构与函数

模块4&#xff1a;常用数据结构 (Organizing Lots of Data) 在前面的模块中&#xff0c;我们学习了如何使用变量来存储单个数据&#xff0c;比如一个数字、一个名字或一个布尔值。但很多时候&#xff0c;我们需要处理一组相关的数据&#xff0c;比如班级里所有学生的名字、一本…

【C++算法】61.字符串_最长公共前缀

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;解释 题目链接&#xff1a; 14. 最长公共前缀 题目描述&#xff1a; 解法 解法一&#xff1a;两两比较 先算前两个字符串的最长公共前缀&#xff0c;然后拿这个最长公共前缀和后面一个来比较&…

JVM 调优不再难:AI 工具自动生成内存优化方案

在 Java 应用程序的开发与运行过程中&#xff0c;Java 虚拟机&#xff08;JVM&#xff09;的性能调优一直是一项极具挑战性的任务&#xff0c;尤其是内存优化方面。不合适的 JVM 内存配置可能会导致应用程序出现性能瓶颈&#xff0c;甚至频繁抛出内存溢出异常&#xff0c;影响业…

纷析云开源财务软件:企业财务数字化转型的灵活解决方案

纷析云是一家专注于开源财务软件研发的公司&#xff0c;自2018年成立以来&#xff0c;始终以“开源开放”为核心理念&#xff0c;致力于通过技术创新助力企业实现财务管理的数字化与智能化转型。其开源财务软件凭借高扩展性、灵活部署和全面的功能模块&#xff0c;成为众多企业…

【数字图像处理】数字图像空间域增强(3)

图像锐化 图像细节增强 图像轮廓&#xff1a;灰度值陡然变化的部分 空间变化&#xff1a;计算灰度变化程度 图像微分法&#xff1a;微分计算灰度梯度突变的速率 一阶微分&#xff1a;单向差值 二阶微分&#xff1a;双向插值 一阶微分滤波 1&#xff1a;梯度法 梯度&#xff1…

基于Linux的ffmpeg python的关键帧抽取

1.FFmpeg的环境配置 首先强调&#xff0c;ffmpeg-python包与ffmpeg包不一样。 1) 创建一个虚拟环境env conda create -n yourenv python3.x conda activate yourenv2) ffmpeg-python包的安装 pip install ffmpeg-python3) 安装系统级别的 FFmpeg 工具 虽然安装了 ffmpeg-p…