《最小生成树算法详解:Kruskal的优雅实现》

前置知识和本篇介绍

前置知识: 数据结构-优先级队列, 数据结构-并查集。
Kruskal算法不需要建图, 因此不会建图的模板也没事。

本篇介绍一最小生成树的概念和Kruskal算法。 有关prim算法(另一种最小生成树的算法), 以及更多优化技巧和刷题本篇不会提及。

《最小生成树算法详解:Kruskal的优雅实现》


一. 引言
  • 什么是最小生成树(MST)?
  • 简要介绍 Kruskal 算法的核心思想和优势。

一家通信公司试图建立其各个计算机中心的通信联系。
它当然可以通过租用电话线连接任意之间的一对, 但不过这样成本太高了。 能保证计算机中心能两两之间有通路即可吗?
是的,以下来自wiki的图,顶点表示计算机中心, 之间连续用边表示, 其中边的权值就是费用。
从一个图中抽掉那些高昂的费用但有不破坏图的连通性。
由于我们只需要保证连通和最低费用就可以了。 任意两个顶点之间只需要一条边连接就足够了。
那么,按照上述删除连通无向图中的边的最终结构会形成一棵树(如下图黑色的边形成的树)。
这颗树就是最小生成树。
在这里插入图片描述

详细部分请向下看
最小生成树的两种算法都是基于贪心的策略, 即寻找局部最优解。
Kruskal算法是一种贪心算法, 它从边的角度出发, 用于带权无向图在寻找最小生成树, 它不需要建图, 只需要用一个高效数据结构并查集就搞定了。
Prim算法留到下一篇再谈。

2. 最小生成树的性质
  • 什么图具有最小生成树:
    • 满足无向,带权,连通这些特征的图具有最小生成树。
  • 最小生成树的定义:
    • 连通图中所有的顶点并且边权重之和最小的树结构
  • 相关性质:
    • 生成树的边数为 n − 1 n-1 n1, 树结构的基本性质, 注:n是顶点的个数。
    • 不会成环。
  • 最小生成树不唯一:
    最小生成树的权值要求最小,但边的组织可能不同, 因此结构并不唯一。 存在多种最小生成树结构(但这些树的最小权重和是相同的)。
3. Kruskal 算法详解
  • 3.1 Kruskal 的核心思想
    • 每次选择最小的边, 将边添加进树结构里。期间可能存在成环情况(借助并查集判环), 直到添加了n-1条边结束。
  • 3.2 算法流程
    1. 若给了图,那么遍历图中所有的边将它们排好序; 或者, 收集好边的信息(两个端点, 权重)排序。
    2. 按边权值升序排序。
    3. 使用并查集判断边是否形成环。(具体看代码)
    4. 逐步加入边,直到添加到n-1条边为止。
  • 3.3 为什么正确性
    基于贪心的策略, 每次选择权值最小的边且这条边不会成环或破坏连通性。 局部最优 == 全局最优。严格证明不必纠结。
4. Kruskal 算法的实现
  • 4.1 数据结构选择
    • 使用并查集(Union-Find)O(1)的时间进行合并, 高效地检测环。
    • 前面可以通过排序数组, 用样可以选择优先级队列或者广泛的堆结构。
  • 4.2 实现细节
    • 对边信息的处理
    • 并查集实现:路径压缩, 按秩排序(我这里代码并未实现)
  • 4.3 Java代码实现
    Kruskal模板题
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Main{//最大数据量public static int MAXN = 5001;public static int MAXM = 200001;//并查集模板数组public static int[] father = new int[MAXN];//边信息的处理public static int[][] edges = new int[MAXM][3];public static int n, m;//初始化并查集public static void build(int n){for(int i=1;i<=n;i++){father[i] = i;}}//向上找标记节点,并完成路径压缩public static int find(int i){if(i != father[i]){father[i] = find(father[i]);}return father[i];}//x,y不属于同一个集合就合并返回true//否则返回false.public static boolean union(int x,int y){int fx = find(x);int fy = find(y);if(fx == fy){return false;}else{father[fx] = fy;return true;}}public static void main(String[] args) throws IOException{BufferedReader br = new BufferedReader(new InputStreamReader(System.in));StreamTokenizer in = new StreamTokenizer(br);PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));while(in.nextToken() != StreamTokenizer.TT_EOF){n = (int)in.nval;in.nextToken();m = (int)in.nval;build(n);for(int i=1;i<=m;i++){in.nextToken();edges[i][0] = (int)in.nval;in.nextToken();edges[i][1] = (int)in.nval;in.nextToken();edges[i][2] = (int)in.nval;}//Kruskal依赖边权值的有序性//比较器快排一下。Arrays.sort(edges,1,m+1,(a,b) -> a[2] - b[2]);int ans = 0;int count = 0;//遍历所有边for(int[] edge : edges){//边的两个顶点不在并查集里, 合并两个并查集//将边添加进最小生成树中。if(union(edge[0], edge[1])){count++;ans += edge[2];}}out.println(count == n-1 ? ans : "orz");}out.flush();out.close();br.close();}
}
5. Kruskal 算法的时间复杂度分析

时间复杂度: O ( m l o g m + n + m ) O(mlogm + n + m) O(mlogm+n+m)
收集边的信息,对边按权值排序, 遍历边生成最小生成树。
并查集操作 O ( 1 ) O(1) O(1), 忽略。

6. Kruskal 算法的优缺点
  • 优点:
    • 适合稀疏图(边数较少)。
    • 算法逻辑清晰易懂。
  • 缺点:
    • 需要对边排序,复杂度较高。
    • 不适合边权值频繁动态更新的情况。

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

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

相关文章

云计算-华为HCIA-学习笔记

笔者今年7月底考取了华为云计算方向的HCIE认证&#xff0c;回顾从IA到IE的学习和项目实战&#xff0c;想整合和分享自己的学习历程&#xff0c;欢迎志同道合的朋友们一起讨论&#xff01; 第二章&#xff1a;服务器基础 服务器是什么&#xff1f; 服务器本质上就是个性能超强的…

uniapp接入高德地图

下面代码兼容安卓APP和H5 高德地图官网&#xff1a;我的应用 | 高德控制台 &#xff0c;绑定服务选择《Web端(JS API)》 /utils/map.js 需要设置你自己的key和安全密钥 export function myAMap() {return new Promise(function(resolve, reject) {if (typeof window.onLoadM…

C++:探索AVL树旋转的奥秘

文章目录 前言 AVL树为什么要旋转&#xff1f;一、插入一个值的大概过程1. 插入一个值的大致过程2. 平衡因子更新原则3. 旋转处理的目的 二、左单旋1. 左单旋旋转方式总处理图2. 左单旋具体会遇到的情况3. 左单旋代码总结 三、右单旋1. 右单旋旋转方式总处理图2. 右单旋具体会遇…

文小言1:

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

uni-app 界面TabBar中间大图标设置的两种方法

一、前言 最近写基于uni-app 写app项目的时候&#xff0c;底部导航栏 中间有一个固定的大图标&#xff0c;并且没有激活状态。这里记录下实现方案。效果如下&#xff08;党组织这个图标&#xff09;&#xff1a; 方法一&#xff1a;midButton的使用 官方文档&#xff1a;ta…

CentOS7(Linux)详细安装教程(图文详解)

一、软件准备 本文CentOS7安装在VMware Workstation虚拟机软件,故安装前请自行安装该软件。VMware Workstation官网链接:VMware Workstation官网地址CentOS7下载地址:centos7镜像 如下是最常使用的版本(任选版本)centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里…

【实战】基于urllib和BeautifulSoup爬取jsp网站的数据

文章目录 前言目标网站分析目标网页爬取数据解析导出数据其他问题处理分页检索及多关键字搜索去重cookie问题工具封装经验总结前言 网络数据爬取大致分为两类: 静态爬取:该种方式针对那种架构比较老的网站,使用模版方式,通过浏览器F12只能找到静态页面,找不到返回json数…

玩转数字与运算:用C语言实现24点游戏的扑克牌魅力

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【MySQL】sql注入相关内容

【MySQL】sql注入相关内容 1. 为什么使用sql注入的时候&#xff0c;url传值的时候要使用–而不是– 使用–进行注释的时候需要在后面加一个空格才可以被认为是注释&#xff0c;url传值的过程中会将空格自动忽略&#xff0c;使用则可以在传输中保留为空格符号。&#xff08;同…

shell脚本(完结)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell编程&#xff08;完结&#xff09;_哔哩哔哩_bilibili 本文主要讲解不同shell脚本中的相互调用以及输入输出重定向操作。 一、不同脚本之间…

【bug】使用transformers训练二分类任务时,训练损失异常大

使用transformers训练二分类任务时&#xff0c;训练损失异常大 问题分析 问题 training_loss异常大&#xff0c;在二分类损失中&#xff0c;收敛在1~2附近&#xff0c;而eval_loss却正常&#xff08;小于0.5&#xff09; 分析 参考&#xff1a; Bug in gradient accumulation…

深入解析 EasyExcel 组件原理与应用

✨深入解析 EasyExcel 组件原理与应用✨ 官方&#xff1a;EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 官网 在日常的 Java 开发工作中&#xff0c;处理 Excel 文件的导入导出是极为常见的需求。 今天&#xff0c;咱们就一起来深入了解一款非常实用的操作 Exce…

Gradio学习笔记记录

安装指令&#xff1a;pip install gradio方法介绍 Interface》用于构建一些简单的页面&#xff0c;可以直接用这个指令搞定 形式》接收三个参数分别为处理函数、输入、输出三部分&#xff0c;呈现一般左/上为输入&#xff0c;右或下为输出 fn&#xff1a;将用户界面 &#xff0…

养老院管理系统+小程序项目需求分析文档

智慧综合养老服务平台是以业务为牵引、场景为驱动&#xff0c;围绕“老人”业务域&#xff0c;持续沉淀和打磨形成适应不同养老业务发展需要的业务能力&#xff0c;推动业务模式升级&#xff0c;为养老服务提供数字化解决方案&#xff0c;并依托实体站点与养老机构实现线上线下…

React的基本知识:事件监听器、Props和State的区分、改变state的方法、使用回调函数改变state、使用三元运算符改变state

这篇教学文章涵盖了大量的React基本知识。 包括&#xff1a; 事件监听器Props和State的区分改变state的方法使用回调函数改变state使用三元运算符改变state处理state中的数组处理state中的object条件渲染 &&条件渲染 三元运算符React中的forms 1. Event Listeners 在…

repmgr安装及常用运维指令

简介 repmgr 由 EDB 与其他个人和组织的贡献一起开发&#xff0c;安装部署相对较为简单 安装 repmgr官网上传对应的安装到服务器上 安装前/etc/hosts IP映射、始终同步、免密通信本文忽略 repmgr的安装相对较为简单,目前repmgr-5仅仅支持到postgresql-15 postgresql必要参数…

opencv-python 分离边缘粘连的物体(距离变换)

import cv2 import numpy as np# 读取图像&#xff0c;这里添加了判断图像是否读取成功的逻辑 img cv2.imread("./640.png") # 灰度图 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊 gray cv2.GaussianBlur(gray, (5, 5), 0) # 二值化 ret, binary cv2…

SATA接口不通分析案例分享

问题&#xff1a; 反馈有台NVR的某个接口SATA不通&#xff08;共有4个SATA接口&#xff0c;采用SATA HUB JMB575&#xff09;&#xff0c;挂载硬盘不上。 分析&#xff1a; 1、直接对换问题口SATA1与正常口SATA2的SATA数据线&#xff0c;SATA1口还是异常&#xff0c;挂在不上…

【Web前端】如何构建简单HTML表单?

HTML 表单是 Web 开发中非常重要的组成部分。它们是与用户交互的主要方式&#xff0c;能够收集用户输入的数据。表单的灵活性使它们成为 HTML 中最复杂的结构之一&#xff0c;但若使用正确的结构和元素&#xff0c;可以确保其可用性和无障碍性。 表单的基本结构 HTML 表单使用…

Flutter:AnimatedIcon图标动画,自定义Icon通过延时Interval,实现交错式动画

配置vsync&#xff0c;需要实现一下with SingleTickerProviderStateMixinclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{// late延迟初始化 AnimationControllerlate AnimationController _controller;overridevoid initStat…