算法.图论-并查集上

文章目录

    • 1. 并查集介绍
    • 2. 并查集的实现
      • 2.1 实现逻辑
      • 2.2 isSameSet方法
      • 2.3 union方法(小挂大优化)
      • 2.4 find方法(路径压缩优化)
    • 3. 并查集模板

1. 并查集介绍

定义:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等
并查集的常见的方法:

方法作用
int find (int)作用就是查找一个元素所在大集合的代表元素, 返回这个元素
boolean isSameSet (int, int)判断传入的两个元素是不是同属一个大集合, 返回T/F
void union (int, int)合并传入的两个元素所代表的大集团(注意不仅仅是这两个元素)

并查集的时间复杂的要求就是实现上述的操作的时间复杂度都是O(1)
下面是关于并查集的一些常见的操作的图示
在这里插入图片描述

2. 并查集的实现

2.1 实现逻辑

不论是哈希表的机构还是list的顺序结构或者是其他的常见的数据结构, 都不可以做到时间复杂度是O(1)的这个指标, 我们直接介绍实现的方式 --> 通过一个father数组以及size数组
关于这两个数组的含义:

数组含义
father下标i代表的是元素的编号, father[i]代表的是他的父亲节点
size下标i代表的是元素的编号, size[i]代表的是这个节点的孩子节点的个数(包括本身)

在这里插入图片描述
初态就是这个样子, 每一个元素的父亲节点都是其本身, 也就是说每一个节点本身就是其所在集合的代表节点, 然后这个集合的大小就是1
下面我们执行操作
step1 : union(a, b)
step2 : union(c, a)
下面是图示(图解一下操作1, 操作2其实是同理的)
在这里插入图片描述
上面的图解也说明了很多问题, 我们的树形结构的挂载的方式是, 小挂大(小的树挂到大树上)
此时进行了union操作之后的逻辑结构就是左下角所示, 此时我们 {a,b} 共属于一个集合, 进行find操作的时候, find(a) 的结果是 b, find(b) 的结果也是 b, 此时size数组中a的值不会再使用了, 因为这时a不可能是领袖节点了, 也就是说这个数据是脏数据…

2.2 isSameSet方法

其实正常来说我们的isSameSet方法和union方法都需要调用find方法, 但是find方法中的路径压缩的技巧是比较重要的, 所以我们单独拎出来放后面说(这里假设已经实现好了), 实现也是比较简单的, 只需要找到这两个元素的代表领袖节点看是不是一个就可以了

	//isSameSet方法private static boolean isSameSet(int a, int b){return find(a) == find(b);}

2.3 union方法(小挂大优化)

解释一下小挂大概念, 在算法导论这本书中说到的是一种秩的概念, 本质上也是为了降低树(集团)的高度所做出的努力, 但这个不是特别必要的…, 也就是在两大集团合并的时候, 小集团(小数目的节点)要依附大集团而存在, 也就是合并的时候, 小集团要挂在大集团上面, 这样可以从一定程度上降低树的高度
代码实现如下

	//union方法private static void union(int a, int b){int fa = find(a);int fb = find(b);if(fa != fb){sets--;if(size[fa] >= size[fb]){father[fb] = fa;size[fa] += size[fb];}else{father[fa] = fb;size[fb] += size[fa];}}}

2.4 find方法(路径压缩优化)

上面的union的小挂大优化, 其实不是特别必要的, 但是我们find方法中的路径压缩是一定要完成的, 如果没有路径压缩的话, 我们的时间复杂度的指标就不会是O(1)
路径压缩指的就是, 在find方法找到父亲节点的时候, 同时把我们的沿途所有节点的父亲节点都改为找到的父亲节点, 以便于操作的时候不用遍历一个长链去寻找父亲节点, 图解如下
在这里插入图片描述
假设我们执行find(a)操作, 就会如图所示把我们的沿途的所有节点的父亲节点都改为领袖节点e
我们借助的是stack栈结构, 或者是递归(其实就是系统栈)实现的

private static final int MAX_CP = 31;private static final int[] father = new int[MAX_CP];private static final int[] size = new int[MAX_CP];private static final int[] stack = new int[MAX_CP];//find方法(路径压缩的迭代实现)private static int find1(int a){int sz = 0;while(father[a] != a){stack[sz++] = a;a = father[a];}while(sz > 0){father[stack[--sz]] = a;}return father[a];}//find方法(路径压缩的递归实现)private static int find(int a){if(father[a] != a){father[a] = find(father[a]);}return father[a];}

3. 并查集模板

上面就是我们关于并查集最基本的分析, 我们提供几个测试链接测试一下

牛客并查集模板

//并查集的基本实现方式
import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.io.OutputStreamWriter;
import java.io.IOException;public class Main {private static final int MAXN = 1000001;private static final int[] father = new int[MAXN];private static final int[] size = new int[MAXN];private static final int[] stack = new int[MAXN];private static int cnt = 0;private static void build(int sz) {cnt = sz;for (int i = 0; i <= cnt; i++) {father[i] = i;size[i] = 1;}}private static int find(int n) {//下面就是扁平化(路径压缩的处理技巧)int capacity = 0;while (father[n] != n) {stack[capacity++] = n;n = father[n];}//开始改变沿途节点的指向while (capacity > 0) {father[stack[--capacity]] = n;}return father[n];}private static boolean isSameSet(int a, int b) {return find(a) == find(b);}private static void union(int a, int b) {//下面的设计就是小挂大的思想int fa = find(a);int fb = find(b);if (fa != fb) {if (size[fa] >= size[fb]) {father[fb] = fa;size[fa] += size[fb];} else {father[fa] = fb;size[fb] += size[fa];}}}//我们使用的是高效率的io工具(使用的其实就是一种缓存的技术)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) {int n = (int)in.nval;build(n);in.nextToken();int m = (int)in.nval;for (int i = 0; i < m; i++) {in.nextToken();int op = (int)in.nval;in.nextToken();int n1 = (int)in.nval;in.nextToken();int n2 = (int)in.nval;if (op == 1) {out.println(isSameSet(n1, n2) ? "Yes" : "No");} else {union(n1, n2);}}}out.flush();out.close();br.close();}
}

洛谷并查集模板

//并查集的基本实现方式
import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.io.OutputStreamWriter;
import java.io.IOException;public class Main {private static final int MAXN = 100001;private static final int[] father = new int[MAXN];private static final int[] size = new int[MAXN];private static final int[] stack = new int[MAXN];private static int cnt = 0;private static void build(int sz){cnt = sz;for(int i = 0; i <= cnt; i++){father[i] = i;size[i] = 1;}}private static int find(int n){//下面就是扁平化(路径压缩的处理技巧)int capacity = 0;while(father[n] != n){stack[capacity++] = n;n = father[n];}//开始改变沿途节点的指向while(capacity > 0){father[stack[--capacity]] = n;}return father[n];}private static boolean isSameSet(int a, int b){return find(a) == find(b);}private static void union(int a, int b){//下面的设计就是小挂大的思想int fa = find(a);int fb = find(b);if(fa != fb){if(size[fa] >= size[fb]){father[fb] = fa;size[fa] += size[fb];}else{father[fa] = fb;size[fb] += size[fa];}}}//我们使用的是高效率的io工具(使用的其实就是一种缓存的技术)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){int n = (int)in.nval;build(n);in.nextToken();int m = (int)in.nval;for(int i = 0; i < m; i++){in.nextToken();int op = (int)in.nval;in.nextToken();int n1 = (int)in.nval;in.nextToken();int n2 = (int)in.nval;if(op == 2){out.println(isSameSet(n1, n2) ? "Y" : "N");}else{union(n1, n2);}}}out.flush();out.close();br.close();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【读书笔记-《30天自制操作系统》-22】Day23

本篇内容比较简单&#xff0c;集中于显示问题。首先编写了应用程序使用的api_malloc&#xff0c;然后实现了在窗口中画点与画线的API与应用程序。有了窗口显示&#xff0c;还要实现关闭窗口的功能&#xff0c;于是在键盘输入API的基础上实现了按下按键关闭窗口。最后发现用上文…

file的判断和获取,创建和删除

常见成员方法 1.length 返回文件的大小(字节数量) 细节1:这个方法只能获取文件的大小&#xff0c;单位是字节如果单位我们要是M&#xff0c;G&#xff0c;可以不断的除以1024 细节2:这个方法无法获取文件夹的大小如果我们要获取一个文件夹的大小&#xff0c;需要把这个文件夹…

视频理解大模型最新进展

文章目录 Video-LLaMAVision-Language BranchAudio-Language Branch Video-ChatGPTMiniGPT4-videoCogVLM2-Video&#xff08;1&#xff09;Pre-training&#xff08;2&#xff09;Post-training Qwen2-VLMA-LMMChat-UniVi大模型对比 Video-LLaMA 2023&#xff1a;阿里达摩院的…

【Python机器学习】NLP信息提取——值得提取的信息

目录 提取GPS信息 提取日期 如下一些关键的定量信息值得“手写”正则表达式&#xff1a; GPS位置&#xff1b;日期&#xff1b;价格&#xff1b;数字。 和上述可以通过正则表达式轻松捕获的信息相比&#xff0c;其他一些重要的自然语言信息需要更复杂的模式&#xff1a; 问…

不小心把U盘格式化了怎么恢复?教你轻松找回数据

U盘作为我们日常工作和生活中的重要数据存储工具&#xff0c;其便携性和大容量深受用户喜爱。然而&#xff0c;不小心将U盘格式化&#xff0c;导致重要数据丢失&#xff0c;是许多人都可能遇到的问题。 当这种突发情况发生时&#xff0c;我们应该如何迅速有效地恢复被格式化的…

Qt 模型视图(二):模型类QAbstractItemModel

文章目录 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel1.基本概念1.1.模型的基本结构1.2.模型索引1.3.行号和列号1.4.父项1.5.项的角色1.6.总结 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel ​ 模型/视图结构是一种将数据存储和界面展示分离的编程方法。模…

Vue.js与Flask/Django后端配合详细讲解

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

JZ2440下载后设置NAND启动文件系统

&#xff08;一&#xff09;下载 &#xff08;二&#xff09;设置根文件系统NAND FLASH启动 set bootargs noinitrd root/dev/mtdblock3 init/linuxrc consolettySAC0

xuri/excelize简单使用

main.go文件&#xff1a; package mainimport ("fmt""github.com/xuri/excelize/v2" )func main() {read() // 读excel文件//write() // 写excel文件//readAndWrite() // 读写excel文件 }func read() {f, err : excelize.OpenFile("read.xls…

YoloV8改进策略:BackBone改进|Next-ViT主干赋能下的革命性改进

摘要 Next-ViT(下一代视觉Transformer)是专为解决传统ViT模型在工业部署中遇到的推理速度慢、计算复杂度高等问题而设计的。它巧妙地结合了高效的Next Convolution Block(NCB)和Next Transformer Block(NTB),通过创新的混合策略(NHS)堆叠这些模块,从而在各种视觉任务…

倍增练习(1)

A - ST 表 && RMQ 问题 题目思路:st表的板子题用于静态区间求最值,通过倍增的思想,先通过预处理将各个区间的最大值通过转移式求出f[i][j] max(f[i][j - 1], f[i (1 << (j - 1))][j - 1]);然后再进行重叠查询查询,k log2(r - l 1);,max(f[l][k], f[r - (1 &l…

安装idea完整教程

安装idea完整教程 下载链接 https://www.jetbrains.com.cn/idea/download/?sectionwindows 安装 安装完成&#xff01; 激活 从网上查找激活码&#xff0c;然后进行激活 我是用的网上找的&#xff0c;大家可以试试&#xff1a;https://www.cnblogs.com/unclecode1024/p/…

OpenCV运动分析和目标跟踪(3)计算图像序列的加权平均值函数accumulateWeighted()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 更新一个运行平均值。 该函数计算输入图像 src 和累积器 dst 的加权和&#xff0c;使得 dst 成为帧序列的运行平均值&#xff1a; dst ( x , y…

FPGA第 11 篇,Verilog 系统函数( Verilog 中的系统函数)

前言 Verilog 作为一种强大的硬件描述语言&#xff0c;不仅提供了用于设计和仿真数字电路的基础语法&#xff0c;还包含了丰富的系统函数&#xff0c;帮助我们高效地完成复杂的硬件操作。系统函数是 Verilog 语言中预定义的特殊函数&#xff0c;通常以 $ 开头&#xff0c;它们…

【Linux】环境部署kafka集群

目录 一、kafka简介 1. 主要特点 2.组件介绍 3.消息中间件的对比 二、环境准备 1.Java环境 2.Zookeeper环境 3.硬件环境集群 三、Zookeeper的集群部署 1.下载zookeeper 2.部署zookeeper集群 &#xff08;1&#xff09;node1节点服务器 &#xff08;2&#xff09;no…

助力电商升级,智象未来(HiDream.ai)开启未来商业新篇章

近日&#xff0c;智象未来&#xff08;HiDream.ai&#xff09;凭借其创新性的“秩象™大模型”&#xff0c;在业界掀起了一场跨行业的创意革命&#xff0c;对视觉设计、运营商服务、品牌营销以及文旅传媒等领域的创新发展产生了深远影响。致力于全球领先的多模态生成式人工智能…

springCloud(一)注册中心

1.Eureka 要是user-service服务有多个&#xff0c;order-service该怎么调用&#xff1f; 这就需要用到 注册中心 了 。 1.1 搭建Eureka服务 1. pom引入依赖 <dependencies><!--eureka服务端--><dependency><groupId>org.springframework.cloud</gr…

VulnHub-Bilu_b0x靶机笔记

Bilu_b0x 靶机 概述 Vulnhub 的一个靶机&#xff0c;包含了 sql 注入&#xff0c;文件包含&#xff0c;代码审计&#xff0c;内核提权。整体也是比较简单的内容&#xff0c;和大家一起学习 Billu_b0x.zip 靶机地址&#xff1a; https://pan.baidu.com/s/1VWazR7tpm2xJZIGUS…

操作系统之磁盘

目录 一. 磁盘的结构二. 磁盘调度算法&#xff08;重点&#xff09;三. 减少磁盘延迟时间的方法四. 磁盘的管理五. 固态硬盘&#xff08;SSD&#xff09; \quad 一. 磁盘的结构 \quad 最内侧磁道上的扇区面积最小&#xff0c;因此数据密度最大 \quad 二. 磁盘调度算法&…

论文阅读与分析:Few-Shot Graph Learning for Molecular Property Prediction

论文阅读与分析&#xff1a;Few-Shot Graph Learning for Molecular Property Prediction 论文地址和代码地址1 摘要2 主要贡献3 基础知识Meta Learning1 介绍2 学习算法Step 1: What is learnable in a learning algorithm?Step 2&#xff1a;Define loss function for learn…