Java——并查集

news2024/9/30 23:23:25

概念

当我们将多个元素分配到不同的集合中,这些集合有的是相关的,有的是不相关的。并查集就是用来查找两个元素是否在同一个集合中的

其主要实现方式是:将所有的元素以下标的形式存储在数组中。例如一共有十个人,那么就将这些人编号为0到9,然后用0到9的下标表示这些人,初始数组存储的全是-1
在这里插入图片描述

数组中存储的数据则代表他们之间的关联方式,例如0,6,7,8互相认识,那么他们就是一个集合,而0号是这个集合中的老大,那么0下标就存储这个团体的人的个数的相反数:-4,其他的几个成员6,7,8,则分别存储他们认识的0的下标:0

如果我们还有另两个集合,例如1,4,9是一个集合,1是老大,4和9存储1的下标,那么4和9存储1,1下标存储-3,而2,3,5是另一个集合,2是老大,则3,5存储2下标,2存储-3

在这里插入图片描述
当我们的集合1和集合2的某一位互相认识了,那么根据朋友的传递原理,我们的集合1和集合2就都互相认识了,那么就会变成一个更大的集合,其中如果让0做老大,1隶属于0下标,那么就会形成下面的样子

0下标就存储了这个大集合的人数的相反数:-7,而1则从老大变成了平民,因此存储老大的下标:0,其他的都是不变的
在这里插入图片描述
通过上面这个基本的原理,我们可以自己实现一个并查集

MyUnionFindSet

变量和构造方法

我们的底层数据结构是数组,在创建的时候,需要给数组传递一个创建的大小,并且用Arrays.fill方法,将数组的全部元素置为-1

public int[] elem;

public MyUnionFindSet(int n){
    this.elem = new int[n];
    Arrays.fill(elem, -1);//初始化数组全为-1
}

寻找根节点

这个方法就是用来找集合中的老大的
通过之前的概念的介绍,我们知道,只有老大存储的是负数,而其他下标则存储其父节点的下标。所以我们可以用一个循环,当这个下标对应的数据不是负数,那么就让x变为这个下标对应的数据,直到找到负数,就返回这个x

在这里插入图片描述
例如我们这个图中,如果我们传递的参数是9,那么elem[9]是1,那么x就变成1,elem[1]是0,那么x就变成0,elem[0]是-7,所以0是根节点,返回0

/**
 * 查找x下标数据的根节点
 * @param x
 * @return 根节点的下标
 */
public int findRoot(int x){
    if(x < 0){
        throw new ArrayIndexOutOfBoundsException("下标不能是负数");
    }

    while(elem[x] >= 0){
        x = elem[x];
    }
    return x;
}

判断两节点是否在同一个集合

当两个节点在同一个集合中,说明他们的根节点一定是相通的,所以我们可以调用findRoot方法,来找到两个节点的根节点,判断是否相同,相同返回true,不同返回false
在这里插入图片描述

/**
 * 查询x1和x2是否在同一个集合中
 * @param x1
 * @param x2
 * @return
 */
public boolean isSameUnionFindSet(int x1, int x2){
    int index1 = findRoot(x1);
    int index2 = findRoot(x2);

    if(index1 == index2){
        return true;
    }
    return false;
}

合并两个集合

通过刚才的图片我们可以知道,当两个节点相连时,如果这两个节点不是根节点,那么就应该找到这两个节点的根节点,如果根节点相同,说明这两个节点已经在同一个集合中了,那么就不用合并了。

而如果根节点不相同,那么就和我们刚才讲的情形类似,就是把0和1相连,这时改变的只有0下标的值和1下标的值,其他的下标的值都是不变的

我们可以看到,0下标的值变成了两个集合的节点数目的总和的相反数,也就是0下标的值加上1下标的值:-7,而1下标的值则是直接改为了0
在这里插入图片描述

在这里插入图片描述
所以,我们就先找到x1,x2的根节点,判断是否相等,相等则直接返回。我们这里实现的逻辑x1是0,x2是1,所以

elem[0] = elem[0] + elem[1]
elem[1] = 0

也就是:

elem[index1] = elem[index1] + elem[index2]
elem[index2] = index1

完整代码如下:

/**
 * 合并x1,x2所在的两个集合
 * @param x1
 * @param x2
 */
public void union(int x1, int x2){
   int index1 = findRoot(x1);
   int index2 = findRoot(x2);

   if(index1 == index2){
       System.out.println("x1和x2已经在同一个集合中了");
       return;
   }

   elem[index1] = elem[index1] + elem[index2];
   elem[index2] = index1;
}

获取集合的个数

可以看到,集合的个数等于所有老大的个数,等于数组中负数的个数

public int getCount(){
    int count = 0;
    for (int x:elem) {
        if(x < 0){
            count++;
        }
    }
    return count;
}

打印

public void print(){
    for (int x:elem) {
        System.out.print(x + " ");
    }
    System.out.println();
}

测试

按照我们上面的图进行合并元素,最终可以得到结果是正确的

public static void main(String[] args) {
    MyUnionFindSet myUnionFindSet = new MyUnionFindSet(10);
    System.out.println("合并0和6");
    myUnionFindSet.union(0,6);
    System.out.println("合并0和7");
    myUnionFindSet.union(0,7);
    System.out.println("合并0和8");
    myUnionFindSet.union(0,8);

    System.out.println("合并1和4");
    myUnionFindSet.union(1,4);
    System.out.println("合并1和9");
    myUnionFindSet.union(1,9);
    System.out.println("合并2和3");
    myUnionFindSet.union(2,3);
    System.out.println("合并2和5");
    myUnionFindSet.union(2,5);

    myUnionFindSet.print();

    System.out.println("合并8和1");
    myUnionFindSet.union(8,1);

    myUnionFindSet.print();

    System.out.println("查找是否为同一个集合");
    System.out.println(myUnionFindSet.isSameUnionFindSet(6,9));
    System.out.println(myUnionFindSet.isSameUnionFindSet(8,2));
}

在这里插入图片描述

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

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

相关文章

C语言tips-野指针

0.写在最前 最近因为工作需要开始重新学c语言&#xff0c;越学越发现c语言深不可测&#xff0c;当初用python轻轻松松处理的一些数据&#xff0c;但是c语言写起来却异常的复杂&#xff0c;这个板块就记录一下我的c语言复习之路 1. 什么是野指针&#xff1f; 如果一个指针指向的…

一文带你深入理解【Java基础】· IO流(上)

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

机器学习100天(五):005 数据预处理之划分训练集

机器学习100天,今天讲的是:数据预处理之划分训练集。 在上一节,我们对类别特征进行了编码,X 和 y 已经变成了机器学习可以理解和处理的数据格式。 下面我们就要对数据集进行划分,划分成训练集和测试集。 在监督式机器学习中,我们一般使用训练集的数据来训练模型,然后…

【LVGL学习笔记】(二) 基础概念

LVGL全程LittleVGL&#xff0c;是一个轻量化的&#xff0c;开源的&#xff0c;用于嵌入式GUI设计的图形库。并且配合LVGL模拟器&#xff0c;可以在电脑对界面进行编辑显示&#xff0c;测试通过后再移植进嵌入式设备中&#xff0c;实现高效的项目开发。 LVGL中文教程手册&#…

心理健康网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 管理员功能&#xff1a; 1、管理关于我们、联系我们 2、管理文章类型、添加心理文章 3、审核咨询师注册信息 4、查看咨询…

我的创作纪念日——为什么要写博客

文章目录收获意义憧憬收获 转载和摘抄只是对知识的搜集&#xff0c;不仅不会起到扩充知识体系的作用&#xff0c;反而会让人陷入盲目的自信或者自卑。一些人会把收藏当作底蕴&#xff0c;例如看到一个如何快速学Python的标题&#xff0c;就会逢人说自己会Python&#xff1b;另…

哈夫曼树,哈夫曼编码及应用——(代码实现)

哈夫曼树&#xff0c;哈夫曼编码及应用1.哈夫曼树1.1 什么是哈夫曼树2.如何构造哈夫曼树&#xff08;哈夫曼算法&#xff09;2.1 举例实现哈夫曼树2.1.1手动实现具体步骤2.1.2代码实现具体步骤3.哈夫曼编码3.1 什么是哈夫曼编码3.2哈夫曼编码的具体实现END!!!1.哈夫曼树 路径长…

零基础可以学习Python吗?转行小白怎么学Python?

ython学习常用的技巧有这些&#xff1a;一是要明确自己的学习目的;二是从易到难&#xff0c;循序渐进;三是合理的选择资料&#xff0c;有所取舍;四是坚定自己的信念。以下是关于Python学习技巧的具体介绍。 1、明确自己的学习目的 每个人学Python的初衷绝对是不一样的&#xf…

【观察】Akamai:向分布式云迈出坚实一步,让云和边缘“无处不在”

近年来&#xff0c;云正如同日常生活中的水、电那样&#xff0c;融入到社会的各个层面&#xff0c;它不再是一种单纯的架构或者技术&#xff0c;而是千行百业走向数字化的核心基础设施&#xff1b;云也正在变成一种融合剂&#xff0c;无论是大数据、人工智能、物联网等&#xf…

多目标背包问题:MOJAYA求解多目标背包问题(Multi-objective Knapsack Problem,MOKP)提供Matlab代码

一、多目标背包问题 1.1多目标背包问题描述 多目标背包问题(Multi-objective Knapsack Problem&#xff0c;MOKP)是一种重要的组合优化问题&#xff0c;在生活的许多领域都有着十分广泛的应用。多目标背包问题可以描述为&#xff1a;给定一个背包和n种物品&#xff0c;其中&a…

docker-compose安装gogs

1.gogs是什么 Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发&#xff0c;并且支持 Go 语言支持的 所有平台&#xff0c;包括 Linux、Mac OS X、Windows 以及 ARM 平台。 2.准备工作gogs 在安装软…

论文精读:《FCOS3D: Fully Convolutional One-Stage Monocular 3D Object Detection》

文章目录论文精读摘要&#xff08;Abstract&#xff09;1. 介绍&#xff08;Introduction&#xff09;2. 相关工作&#xff08;Related Work&#xff09;3. 方法&#xff08;Approach&#xff09;3.1 框架总览(Framework Overview)3.2 2D引导的多层次3D预测(2D Guided Multi-Le…

【java】javac 相关API JavaCompiler StandardJavaFileManager AbstractProcessor

1.概述 转载并且补充:Java 编译器 javac 笔记:javac API、注解处理 API 与 Lombok 原理 看这个文章之前首先看:【java】java JSR 269 自定义注解实战 Lombok @Data注解 java版本直接调用 javac 是 Java 代码的编译器 [openjdk, oracle ],初学 Java 的时候就应该接触过。…

马上跨年了,如何用代码写一个“跨年倒计时”呢?

前言 大家好&#xff0c;我是陈橘又青&#xff0c;再过两周就是新的一年了&#xff0c;作为一名有仪式感的程序员&#xff0c;今天我们就来制作一个简单的跨年倒计时小网页&#xff0c;祝看到的所有人新年快乐&#xff01;&#xff08;附上完整源码&#xff0c;需要的小伙伴自取…

八、Docker 安装Mysql(流程、注意点、实例)

Docker 安装mysql 要不 安装tomcat 稍微复杂些,要配置一些参数,例如mysql密码,配置文件编写等。 1、docker hub上面查找mysql镜像 地址:Docker Hub 可以拉取最新的,也可以按照tag搜索自己想要的版本,拉取 2、从docker hub上拉取mysql5.7镜像到本地 命令:docker pull …

【实时数仓】DWM层设计模式、独立访客(UV)的计算

文章目录一 DWS层与DWM层的设计1 设计思路2 DWS层需求分析二 DWM层-UV计算1 需求分析与思路2 从kafka中读取数据&#xff08;1&#xff09;代码实现&#xff08;2&#xff09;测试&#xff08;3&#xff09;总结3 UV过滤 -- 独立访客计算&#xff08;1&#xff09;实现思路&…

Spring+SpringMVC+MP登录案例(含拦截器)

技术框架 后端&#xff1a;Spring、Spring MVC、Mybatis-Plus 前端&#xff1a;HTML、CSS、Layui、JS、Jquery 功能模块技术 1、用户的每一个请求使用了SpringMVC 拦截器技术&#xff0c;没有登录的用户自动重定向到登录页 2、统一请求模式&#xff0c;使用Restful风格对后端…

贤鱼的刷题日常(数据结构栈学习)-1551:Sumsets--题目详解

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;例题讲解1551:Sumsets ✅创作者&#xff1a;贤鱼 ⏰预计时间&#xff1a;25分钟 &#x1f389;个人主页&#xff1a;贤鱼的个人主页 &#x1f525;专栏系列&#xff1a;c &#x1f341;贤鱼的个人社区&#xff0c;欢迎你的…

学Python的理由有哪些?这四大理由足够了

学Python的理由有哪些&#xff1f;可能有人会说Python是一种计算机语言&#xff0c;具有简洁性、易读性、及可扩展性&#xff0c;相对于其他语言学起来会更加容易&#xff0c;目前应用也非常广泛等等。其实总结起来&#xff0c;学Python的理由不外乎四点&#xff0c;即丰富免费…

Python数据分析主要功能是什么?可以用来做什么?

Python是一种计算机程序设计语言&#xff0c;具有简洁性、易读性以及可扩展性&#xff0c;相较于其他语言学习起来更加容易。随着互联网的发展&#xff0c;Python知识也被越来越多的人所熟知。但还是有很多人不了解它究竟可以用来做什么&#xff0c;接下来就跟随我了解一下吧&a…