【算法基础实验】图论-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…

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…

企业计算机服务器中了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…

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

在学习数据结构前&#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;接口调用有…

Mudem,打造私密安全、高效稳定的私人空间

Mudem 是 Codigger 平台中的一个关键组件&#xff0c;它提供基础通讯服务&#xff0c;确保不同类型的机器之间可以进行安全和高效的连接。它其设计理念在于将本地机器、公有云以及私有云上的设备无缝地整合为一个可远程在线访问的工作站&#xff08;Workstation&#xff09;。这…

【数据库】MongoDB

文章目录 [toc]数据库操作查询数据库切换数据库查询当前数据库删除数据库查询数据库版本 数据集合操作创建数据集合查询数据集合删除数据集合 数据插入插入id重复的数据 数据更新数据更新一条丢失其他字段保留其他字段 数据批量更新 数据删除数据删除一条数据批量删除 数据查询…

Python脚本实现PC端大麦网自动购票(Selenium自动化测试工具)

文章目录 Selenium 简介Selenium webdriver 文档chromedriver&#xff08;谷歌浏览器驱动&#xff09;chromedriver 下载配置环境变量 大麦网购票脚本网页 dom 元素 启用远程调试&#xff08;操作已打开的窗口&#xff09; Selenium 简介 Selenium 是一个用于自动化测试的工具…

如何查看自己的公网IP?

我们在网络中&#xff0c;每一个设备都被分配了一个唯一的IP地址&#xff0c;用以区分和识别其他设备。公网IP地址是指可被公众访问的IP&#xff0c;是因特网上的全球唯一标识。当我们需要查看自己的公网IP时&#xff0c;可以采取以下几种方式。 使用命令行查看公网IP 在Windo…

算法06链表

算法06链表 一、链表概述1.1概述1.2链表的组成部分&#xff1a;1.3链表的优缺点&#xff1a; 二、链表典例力扣707.设计链表难点分析&#xff1a;&#xff08;1&#xff09;MyLinkedList成员变量的确定&#xff1a;&#xff08;2&#xff09;初始化自定义链表&#xff1a;&…

06.JAVAEE之线程4

1.定时器 1.1 定时器是什么 定时器也是软件开发中的一个重要组件. 类似于一个 " 闹钟 ". 达到一个设定的时间之后 , 就执行某个指定好的代码. 约定一个时间,时间到达之后,执行某个代码逻辑, 定时器非常常见,尤其是在进行网络通信的时候, 需要有等待的最大时间&…