【算法基础实验】图论-UnionFind连通性检测之quick-union

Union-Find连通性检测之quick-union

理论基础

在图论和计算机科学中,Union-Find 或并查集是一种用于处理一组元素分成的多个不相交集合(即连通分量)的情况,并能快速回答这组元素中任意两个元素是否在同一集合中的问题。Union-Find 特别适用于连通性问题,例如网络连接问题或确定图的连通分量。

Union-Find 的基本操作

Union-Find 数据结构支持两种基本操作:

  1. Union(合并): 将两个元素所在的集合合并成一个集合。
  2. Find(查找): 确定某个元素属于哪个集合,这通常涉及找到该集合的“代表元素”或“根元素”。

Union-Find 的结构

Union-Find 通常使用一个整数数组来表示,其中每个元素的值指向它的父节点,这样形成了一种树形结构。集合的“根元素”是其自己的父节点。

Union-Find 的优化技术

为了提高效率,Union-Find 实现中常用两种技术:

  1. 路径压缩(Path Compression): 在执行“查找”操作时,使路径上的每个节点都直接连接到根节点,从而压缩查找路径,减少后续操作的时间。
  2. 按秩合并(Union by Rank): 在执行“合并”操作时,总是将较小的树连接到较大的树的根节点上。这里的“秩”可以是树的深度或者树的大小。

应用示例

Union-Find 算法常用于处理动态连通性问题,如网络中的连接/断开问题或者图中连通分量的确定。例如,Kruskal 的最小生成树算法就使用 Union-Find 来选择边,以确保不形成环路。

总结

Union-Find 是解决连通性问题的一种非常高效的数据结构。它能够快速合并集合并快速判断元素之间的连通性。通过路径压缩和按秩合并的优化,Union-Find 在实际应用中可以接近常数时间完成操作。因此,它在算法竞赛、网络连接和社交网络分析等领域有广泛的应用。

数据结构

private int[] id // 分量id(以触点作为索引)
private int count // 分量数量

实验数据和算法流程

本实验使用tinyUF.txt作为实验数据,数据内容如下,一共定义了10对连通性关系

10
4 3
3 8
6 5
9 4
2 1
8 9
5 0
7 2
6 1
1 0
6 7

实验的目的是检测数据中共有多少个连通分量,并打印每个元素所属的连通分量编号

下图展示了处理5和9连通性的一个瞬间

请添加图片描述

完整流程如下

请添加图片描述

代码实现

原则是小树挂在大树下,如果一棵高度为1,但是有100个节点的树,要把高度为2的三节点小树挂在这课大树上

可以想象如果反过来,大树挂在小树下,大树的100个节点都将变成高度为3的树枝,这样的话查询的整体成本就太高了

import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdIn;public class myQuickUnion {private int[] id;private int count;private int finds;private int[] size;public myQuickUnion(int N) { // 初始化分量id数组count = N;id = new int[N];for (int i = 0; i < N; i++) id[i] = i;size = new int[N];for (int i = 0; i < N; i++) size[i] = 1;}public boolean connected(int p, int q){return find(p) == find(q);}public int count(){ return count;}private int find(int p){while(p != id[p]){p = id[p];finds ++;}return p;}public void union(int p, int q){int pRoot = find(p);int qRoot = find(q);if(pRoot==qRoot) return;if(size[pRoot]<size[qRoot]){id[pRoot]=qRoot;size[qRoot]+=size[pRoot];}else{id[qRoot]=pRoot;size[pRoot]+=size[qRoot];}//id[pRoot] = qRoot;//此处注释掉的是随机将两棵树的根连接的表达式//根据实测,加权时总的find次数为2000左右,普通union为2万次左右count --;}public static void main(String[] args){int N = StdIn.readInt();myQuickUnion qu = new myQuickUnion(N);while(!StdIn.isEmpty()){int p = StdIn.readInt();int q = StdIn.readInt();if(qu.connected(p,q)) continue;qu.union(p,q);}StdOut.println("components: "+qu.count);for(int i=0;i<N;i++){StdOut.println(i+":"+qu.id[i]);}StdOut.println("find counts: "+qu.finds);}
}

代码详解

这段代码是一个实现了“加权快速合并”(Weighted Quick Union)的并查集算法的Java类 myQuickUnion。该算法用于处理大量元素的动态连通性问题,提高了普通快速合并(Quick Union)算法的效率。以下是对这段代码的详细解释:

类定义和变量


public class myQuickUnion {private int[] id;     // id数组,用于保存每个节点的父节点private int count;    // 连通分量的数量private int finds;    // 进行find操作的次数统计private int[] size;   // 每个根节点相应的分量大小
  • id 数组中,每个位置保存了该位置元素的父节点索引。
  • count 记录当前图中连通分量的数量。
  • finds 用于记录执行 find 操作的次数,有助于分析算法性能。
  • size 数组用于保存以每个节点为根的树的大小。

构造函数


public myQuickUnion(int N) {count = N;id = new int[N];for (int i = 0; i < N; i++) id[i] = i;size = new int[N];for (int i = 0; i < N; i++) size[i] = 1;
}

构造函数初始化了 id 数组和 size 数组。id 数组的每个元素初始指向自身,表示每个元素都是自己的根节点。size 数组中的每个元素初始为 1,表示每个根节点的树大小为 1。

方法实现

connected


public boolean connected(int p, int q) {return find(p) == find(q);
}

检查两个元素是否连通,即它们是否有相同的根。

find


private int find(int p) {while (p != id[p]) {p = id[p];finds++;}return p;
}

找到元素 p 的根节点。这里使用了路径压缩的一种简单形式,在找根的过程中顺便统计操作次数。

union


public void union(int p, int q) {int pRoot = find(p);int qRoot = find(q);if (pRoot == qRoot) return;if (size[pRoot] < size[qRoot]) {id[pRoot] = qRoot;size[qRoot] += size[pRoot];} else {id[qRoot] = pRoot;size[pRoot] += size[qRoot];}count--;
}

合并两个元素所在的树。如果一个树的大小小于另一个,小的树的根节点将指向大的树的根节点,并更新树的大小。这种“按大小加权”的策略有助于减少树的高度,从而提高后续操作的效率。

主函数


public static void main(String[] args) {int N = StdIn.readInt();myQuickUnion qu = new myQuickUnion(N);while (!StdIn.isEmpty()) {int p = StdIn.readInt();int q = StdIn.readInt();if (qu.connected(p, q)) continue;qu.union(p, q);}StdOut.println("components: " + qu.count);for (int i = 0; i < N; i++) {StdOut.println(i + ":" + qu.id[i]);}StdOut.println("find counts: " + qu.finds);
}

在主函数中,从标准输入读取元素数量和成对的整数。每对整数代表一次尝试连接的操作。如果两个元素已经连通,则忽略;否则,进行合并操作。最终,输出连通分量的数量、每个元素的最终根,以及进行 find 操作的总次数。

实验

代码编译

$ javac myQuickUnion.java

代码运行

该算法处理tinyUF.txt时由于使用了加权方法,优先将小树挂在大树下,这样可以极大减少find操作的次数,提高了性能,在打印中可以看到find counts的值为13,即一共执行了13次find,

$ java myQuickUnion < ..\data\tinyUF.txt 
components: 2
0:6
1:2
2:6
3:4
4:4
5:6
6:6
7:2
8:4
9:4
find counts: 13

如果将权重处理注释掉,使用普通quick-union方法,find counts数值会变为16,影响性能

如果导入mediumUF.txt或者largeUF.txt数据,这个差距将更加悬殊

请添加图片描述

java myQuickUnion < ..\data\tinyUF.txt
components: 2
0:1
1:1
2:1
3:8
4:3
5:0
6:5
7:1
8:8
9:8
find counts: 16

参考资料

算法(第四版) 人民邮电出版社

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

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

相关文章

AI技术宝库:一键收藏全球最全面的人工智能资源网站

1、KKAI&#xff08;kk.zlrxjh.top&#xff09; R5AI是一种融合了星火大模型与文心大模型的知识增强型大语言模型&#xff0c;主要聚焦于自然语言处理&#xff08;NLP&#xff09;的技术开发。 该模型具有卓越的语义理解和文本生成能力&#xff0c;可以有效处理多种复杂的自然语…

python爬虫-----深入了解 requests 库下篇(第二十六天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

M-LAG的基本概念

如图所示&#xff0c;用户侧设备Switch&#xff08;可以是交换机或主机&#xff09;通过M-LAG机制与另外两台设备&#xff08;SwitchA和SwitchB&#xff09;进行跨设备链路聚合&#xff0c;共同组成一个双活系统。这样可以实现SwitchA和SwitchB共同进行流量转发的功能&#xff…

MySQL查出时间比实际晚8小时的解决方案

查询出来的日期数据比数据库中日期数据晚8小时&#xff0c;一开始很懵逼&#xff0c;IDEA 和 server 时区都一样呢&#xff01;后来发现&#xff1a; jdbcUrljdbc:mysql://localhost:hentai?useUnicodetrue&characterEncodingUTF-8&useJDBCCompliantTimezoneShifttru…

C++11单例模式

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

16(第十五章,数据管理成熟度评估)

目录 概述 数据管理成熟度等级 基本概念 评级等级以及特点 现有的DMMA框架 活动 方法 扩展 概述 数据管理成熟度等级 1) 0 级。无能力级。2) 1 级。初始级或临时级&#xff1a;成功取决于个人的能力。3) 2 级。可重复级&#xff1a;制定了最初级的流程规则。4) 3 级。…

【webrtc】m114自己实现的PrioritizedPacketQueue及优先级处理

G:\CDN\WEBRTC-DEV\libwebrtc_build\src\modules\pacing\prioritized_packet_queue.h跟m98不同 :webrtc】m98 RoundRobinPacketQueue的优先级处理,m114直接使用taskqueue顺序处理了。甚至自己实现了优先级队列感觉简化了实现,更为清晰 易读,但是去掉了码率低就优先的逻辑。1…

C 语言实例 - 两个浮点数相乘

输入两个浮点数&#xff0c;计算乘积。 #include <stdio.h>int main() {float num1, num2, product;printf("请输入第一个浮点数: ");scanf("%f", &num1);printf("请输入第二个浮点数: ");scanf("%f", &num2);product …

企业计算机服务器中了rmallox勒索病毒怎么办?Rmallox勒索病毒解密流程工具

在网络飞速发展的时代&#xff0c;企业离不开网络&#xff0c;网络为企业的生产运营提供了极大便利&#xff0c;加快了企业进步的步伐&#xff0c;依靠网络可以开展各项工作业务&#xff0c;通过网络数据整合&#xff0c;可以更方便企业办公。网络在为企业提供便利的同时也为企…

ESLint 、 e2e test 学习

Lint和Format的区别&#xff1a; Lint只会告诉你代码中的错误或者不符合规范的地方&#xff0c;而Format是用来对格式作调整的 HTML/tpl&#xff1a;HTMLLint CSS/SCSS&#xff1a;Stylelint JS/JSX&#xff1a;Eslint JSLint&#xff1a;古老&#xff0c;不能配置和扩展JSHin…

【C++类和对象】日期类的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

Post请求中常见的Content-Type类型

Post请求中常见的Content-Type类型的结构 &#xff08;1&#xff09;application/x-www-form-urlencoded 这是浏览器原生的form表单类型&#xff0c;或者说是表单默认的类型。 下面是一个请求实例&#xff1a; 请求报文&#xff1a; 可以看得出&#xff0c;post将请求参数以k…

搭建vue3组件库(一):Monorepo架构搭建

文章目录 1. 以 pnpm 构建 monorepo1.1 全局安装 pnpm1.2 配置 pnpm 的 monorepo 工作区1.3 仓库项目内的包相互调用1.4 TypeScript 初始化配置文件2. 通用配置文件2.1 添加 .editorconfig 编辑器格式配置文件2.2 添加 .gitignore git 忽略文件2.3 添加 .npmrc npm配置文件2.4 …

两个列表联动修改选中标题的时机

在iOS UI中&#xff0c;常常遇到这种场景&#xff0c;就是我们有两个列表&#xff0c;一个 列表是标题&#xff0c;一个列表是分区的内容&#xff0c;我们滚动内容列表的时候&#xff0c;需要选中当前内容列表中对应的标题&#xff0c; 这个时候&#xff0c;我们有多种实现方案…

了解时间复杂度和空间复杂度

在学习数据结构前&#xff0c;我们需要了解时间复杂度和空间复杂度的概念&#xff0c;这能够帮助我们了解数据结构。 算法效率分为时间效率和空间效率 时间复杂度 一个算法的复杂度与其执行的次数成正比。算法中执行基础操作的次数&#xff0c;为算法的时间复杂度。 我们采…

网络安全实训Day23

网络空间安全实训-渗透测试 文件上传攻击 定义 将Webshell文件上传到网站服务器上&#xff0c;从而获得网站整台服务器控制权限的攻击方式 Webshell 一种以网页形式存在的命令行执行环境&#xff0c;又称网页木马 分类 一句话木马 只有一行代码&#xff0c;功能强大&#xff…

【程序分享1】LAMMPS + OVITO + 晶体缺陷识别 + 点缺陷 + 分子动力学模拟

分享2个分子动力学模拟相关的程序。 1. 一种识别体心立方晶体缺陷的新方法。 2. 无后处理的分子动力学模拟中的并行点缺陷识别: lammps的计算和转储方式 。 感谢论文的原作者&#xff01; 第1个程序 关键词&#xff1a; 1. Atomistic simulations, 2. Molecular dynamics…

北京市高级职称破格申报推荐表

北京市高级职称破格申报推荐表 推荐人 基本情况 姓名 证件类型 证件号码 工作单位及职务 专业领域 联系方式 职称 证书编号 授予单位 取得时间 申报人 基本情况 姓名 证件类型 证件号码 工作单位及职务 申报职称 申报级别 申…

PFA容量瓶耐受强酸强碱进口特氟龙材质定容瓶

PFA容量瓶&#xff0c;也叫特氟龙容量瓶&#xff0c;是用于配制标准浓度溶液的实验室器皿&#xff0c;是有着细长颈、梨形肚的耐强腐蚀平底塑料瓶&#xff0c;颈上有标线&#xff0c;可直接配置标准溶液和准确稀释溶液以及制备样品溶液。 因其有着不易碎、材质纯净、化学稳定性…

OpenHarmony实战开发-按钮 (Button)

Button是按钮组件&#xff0c;通常用于响应用户的点击操作&#xff0c;其类型包括胶囊按钮、圆形按钮、普通按钮。Button做为容器使用时可以通过添加子组件实现包含文字、图片等元素的按钮。具体用法请参考Button。 创建按钮 Button通过调用接口来创建&#xff0c;接口调用有…