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

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

理论基础

在图论和计算机科学中,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的一个处理瞬间

请添加图片描述

完整流程如下
请添加图片描述

代码实现

import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdIn;public class myQuickFind
{private int[] id; // 分量id(以触点作为索引)private int count; // 分量数量public myQuickFind(int N){ // 初始化分量id数组count = N;id = new int[N];for (int i = 0; i < N; i++)id[i] = i;}public int count(){ return count; }public boolean connected(int p, int q){ return find(p) == find(q); }public int find(int p){ return id[p]; }public void union(int p, int q){ // 将p和q归并到相同的分量中int pID = find(p);int qID = find(q);// 如果p和q已经在相同的分量之中则不需要采取任何行动if (pID == qID) return;// 将p的分量重命名为q的名称for (int i = 0; i < id.length; i++)if (id[i] == pID) id[i] = qID;count--;}public static void main(String[] args){ // 解决由StdIn得到的动态连通性问题int N = StdIn.readInt(); // 读取触点数量myQuickFind qf = new myQuickFind(N); // 初始化N个分量while (!StdIn.isEmpty()){int p = StdIn.readInt();int q = StdIn.readInt(); // 读取整数对if (qf.connected(p, q)) continue; // 如果已经连通则忽略qf.union(p, q); // 归并分量}StdOut.println(qf.count() + " components");for(int i = 0;i<N;i++){StdOut.println(i + ":"+qf.find(i));}}
}

代码详解

这段代码实现了一种名为 Quick-Find 的并查集算法,用来解决动态连通性问题。下面是详细的代码解读:

类定义和变量


public class myQuickFind {private int[] id; // 分量id(以触点作为索引)private int count; // 分量数量
  • id 数组用来存储每个节点的分量标识。在 Quick-Find 中,id 数组的每个位置的值表示那个位置所属的组。
  • count 记录当前图中连通分量的数量。

构造函数


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

构造函数接受一个整数 N,表示图中节点的数量。初始时,每个节点自成一个连通分量,即每个节点都是自己的代表,因此 id[i] 初始化为 i

辅助方法


public int count() { return count; }
public boolean connected(int p, int q) { return find(p) == find(q); }
public int find(int p) { return id[p]; }
  • count() 返回当前连通分量的数量。
  • connected(p, q) 检查两个节点是否属于同一个连通分量。
  • find(p) 查找节点 p 的连通分量标识。

Union 操作


public void union(int p, int q) {int pID = find(p);int qID = find(q);if (pID == qID) return; // 如果p和q已经在相同的分量之中则不需要采取任何行动for (int i = 0; i < id.length; i++)if (id[i] == pID) id[i] = qID;count--;
}

union(p, q) 方法用于合并包含节点 pq 的两个连通分量。如果两者已经在同一个连通分量中,则不做任何操作。否则,遍历 id 数组,将所有属于 p 的连通分量的节点都重新标记为属于 q 的连通分量。

主函数


public static void main(String[] args) {int N = StdIn.readInt(); // 读取触点数量myQuickFind qf = new myQuickFind(N); // 初始化N个分量while (!StdIn.isEmpty()) {int p = StdIn.readInt();int q = StdIn.readInt(); // 读取整数对if (qf.connected(p, q)) continue; // 如果已经连通则忽略qf.union(p, q); // 归并分量}StdOut.println(qf.count() + " components");for(int i = 0;i<N;i++){StdOut.println(i + ":"+qf.find(i));}
}

主函数从标准输入读取节点数量和一系列整数对。对于每对整数,如果它们不属于同一个连通分量,则调用 union 方法将它们合并。程序的最终输出是图中的连通分量数量,以及每个节点的连通分量标识。

Quick-Find 的性能

Quick-Find 算法的缺点在于 union 操作的高成本,它需要 O(N) 时间来处理每次合并操作,这在处理大量操作时可能变得非常慢。尽管如此,它的 find 操作非常快,只需常数时间 O(1)。因此,这种数据结构适用于不频繁进行 union 操作但需要频繁进行连通性检查的场景。

实验

代码编译

javac myQuickFind.java

代码运行

java myQuickFind < ..\data\tinyUF.txt 
2 components
0:1
1:1
2:1
3:8
4:8
5:1
6:1
7:1
8:8
9:8

参考资料

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

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

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

相关文章

【React】Sigma.js框架网络图-入门篇(2)

通过《【React】Sigma.js框架网络图-入门篇》有了基本认识 由于上一篇直接给出了基本代码示例&#xff0c;可能看着比较复杂也不知道是啥意思&#xff1b; 今天从理论入手重新认识下&#xff01; 一、基本认识 首先&#xff0c;我们先了解下基础术语&#xff1a; 图(Graph)&…

随笔 | 宿舍矛盾

室友A:睡觉时间比较早 室友B:睡觉时间比较晚&#xff0c;起床时间也晚 室友C:睡的晚&#xff0c;起的早 我&#xff1a;睡的时间随机&#xff0c;起的较早 事件1&#xff1a; 某一个星期四的中午&#xff0c;我正在听歌。室友C跟我说&#xff1a;我们去打扫卫生吧。于是&am…

CPPTest实例分析(C++ Test)

1 概述 CppTest是一个可移植、功能强大但简单的单元测试框架&#xff0c;用于处理C中的自动化测试。重点在于可用性和可扩展性。支持多种输出格式&#xff0c;并且可以轻松添加新的输出格式。 CppTest下载地址&#xff1a;下载地址1  下载地址2 下面结合实例分析下CppTest如…

【Linux网络】FTP服务

目录 一、FTP简介 1.FTP-文件传输协议 2.FTP的两种模式 二、安装配置FTP 1.安装环境 2.对文件的操作 3.切换目录 4.设置匿名用户 5.图形化界面登录 6.白名单与黑名单 重点与难点 一、FTP简介 1.FTP-文件传输协议 FTP是FileTransferProtocol&#xff08;文件传输协…

【论文笔记 | 异步联邦】PORT:How Asynchronous can Federated Learning Be?

1. 论文信息 How Asynchronous can Federated Learning Be?2022 IEEE/ACM 30th International Symposium on Quality of Service (IWQoS). IEEE, 2022&#xff0c;不属于ccf认定 2. introduction 2.1. 背景&#xff1a; 现有的异步FL文献中设计的启发式方法都只反映设计空…

php反序列化字符串逃逸

字符串逃逸 字符串逃逸是通过改变序列化字符串的长度造成的php反序列化漏洞 一般是因为替换函数使得字符串长度发生变化&#xff0c;不论变长还是变短&#xff0c;原理都大致相同 在学习之前&#xff0c;要先了解序列化字符串的结构&#xff0c;在了解结构的基础上才能更好理解…

ASP.NET某企业信息管理系统的设计与实现

摘 要 信息管理系统就是我们常说的MIS(Management Information System),它是一个计算机软硬件资源以及数据库的人-机系统。经过对题目和内容的分析,选用了Microsoft公司的ASP.NET开发工具,由于它提供了用于从数据库中访问数据的强大工具集,使用它可以建立开发比较完善的数据库…

汽车底盘域的学习笔记

前言&#xff1a;底盘域分为传统车型底盘域和新能源车型底盘域&#xff08;新能源系统又可以分为纯电和混动车型&#xff0c;有时间可以再研究一下&#xff09; 1&#xff1a;传统车型底盘域 细分的话可以分为四个子系统 传动系统 行驶系统 转向系统 制动系统 1.1传动系…

第29天:安全开发-JS应用DOM树加密编码库断点调试逆向分析元素属性操作

第二十九天 一、JS技术-DOM树操作及安全隐患 1.DOM&#xff1a;文档操作对象 获取HTML代码中函数的值&#xff0c;可以操作网页代码内容&#xff0c;实现自主或用户交互动作反馈 安全问题&#xff1a;本身的前端代码通过DOM技术实现代码的更新修改&#xff0c;但是更新修改如…

鸿蒙APP开发页面组件之间的属性关系

我们将对于多页面以及更多有趣的功能展开叙述&#xff0c;这次我们对于 HarmonyOS 的很多有趣常用组件并引出一些其他概念以及解决方案、页面跳转传值、生命周期、启动模式&#xff08;UiAbility&#xff09;&#xff0c;样式的书写、状态管理以及动画等方面进行探讨 页面之间…

Web前端一套全部清晰 ③ day2 HTML 标签综合案例

别让平淡生活&#xff0c;耗尽所有向往 —— 24.4.26 综合案例 —— 一切都会好的 网页制作思路&#xff1a;从上到下&#xff0c;先整体到局部&#xff0c;逐步分析制作 分析内容 ——> 写代码 ——>保存——>刷新浏览器&#xff0c;看效果 <!DOCTYPE html> &l…

OSPF域间路由

注&#xff1a;区域&#xff08;area&#xff09;是以接口进行划分的 描述&#xff1a; R1的g0/0/1接口属于area 0 √ R1属于区域0和区域1 1.设计原则 1、OSPF区域的设计原则&#xff1a; 骨干区域有且只能存在一个 非骨干区域必须和骨干区域相连 多区域时&#…

SystemUI KeyButtonView setDarkIntensity 解析

继承自 ImageView KeyButtonDrawable intensity为0时按键颜色为白色。 intensity为1时黑色为的调用堆栈&#xff1a; java.lang.NullPointerException: Attempt to invoke virtual method int java.lang.String.length() on a null object referenceat com.android.systemui.…

【JAVA】UDP与TCP套接字编程

目录 一、UDP数据报套接字编程 1、DatagramSocket API 2、DatagramPacket API 3、InetSocketAddress API 4、示例一 5、示例二 二、TCP流套接字编程 1、ServerSocket API 2、Socket API 3、TCP中的长短连接 4、示例一 5、示例二 一、UDP数据报套接字编程 1、Datag…

施耐德 Unity Pro 编程软件导入导出变量

适用范围 施耐德中高端PLC&#xff0c;使用的编程软件为 UnityPro &#xff08;最新版更名为 Ecostructure Control Expert&#xff09; 中端 PLC&#xff1a;Premium&#xff0c;M340高端 PLC&#xff1a;Quantum&#xff0c;M580 导出/导入变量 导出变量可导出【变量和 FB…

Java设计模式 _创建型模式_原型模式(Cloneable)

一、原型模式 1、原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能比较好。一般对付出较大代价获取到的实体对象进行克隆操作&#xff0c;可以提升性能。 2、实现思路&#xff1a; &#xff08;1&#xff09;、需要克隆的…

C基础语法速览

叠甲&#xff1a;以下文章主要是依靠我的实际编码学习中总结出来的经验之谈&#xff0c;求逻辑自洽&#xff0c;不能百分百保证正确&#xff0c;有错误、未定义、不合适的内容请尽情指出&#xff01; 文章目录 1.数据类型1.1.数据类型的常见分类1.2.数据类型的符号修饰1.3.数据…

面向对象设计与分析40讲(25)中介模式、代理模式、门面模式、桥接模式、适配器模式

文章目录 门面模式代理模式中介模式 之所以把这几个模式放到一起写&#xff0c;是因为它们的界限比较模糊&#xff0c;结构上没有明显的差别&#xff0c;差别只是语义上。 这几种模式在结构上都类似&#xff1a; 代理将原本A–>C的直接调用变成&#xff1a; A–>B–>…

git 基础知识(全能版)

文章目录 一 、git 有三个分区二、git 基本操作1、克隆—git clone2、拉取—git fetch / git pull3、查看—git status / git diff3.1 多人开发代码暂存技巧 本地代码4、提交—git add / git commit / git push5、日志—git log / git reflog6、删除—git rm ‘name’7、撤销恢…

【C++】详解初始化列表,隐式类型转化,类静态成员,友元

前言 初始化列表是对构造函数内容的补充&#xff0c;小编会详细的讲解初始化列表的概念&#xff0c;特性&#xff0c;注意点。这是本篇内容的重头戏&#xff0c;小编会先提一个问题来抛砖引玉。 隐式类型转换顾名思义&#xff0c;首先它不需要主动转换&#xff0c;然后就是不同…