并查集是什么?怎么模拟实现?如何应用?

news2024/11/24 1:59:19

目录

一、什么是并查集?

二、并查集可以解决哪些问题?

三、并查集的模拟实现

3.1、并查集的定义

3.2、查询两个元素是否是同一个集合

3.3、合并两个集合

3.4、求集合个数

3.5、并查集完整代码

小结


一、什么是并查集?

        我们可以想象这样一个过程,开始时有n个元素,某些元素开始和其他元素按照一定规律进行集合合并,有可能就会分成几个集合。在这个过程中要反复某个元素是哪个集合的,这样的运算,被抽象成数据类型叫做“并查集”;

还是不太理解?举个例子

        例如:现在有10个人,分别对其进行编号,下标都为-1(为什么是-1,后面会解释),如下图:

 

现在将这个一个个零散人组建成如下三个团体:

 他们的下标被修改为:

 解释:

1. 数组的下标对应集合中元素的编号

2. 数组中如果为负数,负号表示当前下标为根结点,数字代表该集合中元素个数

3. 数组中如果为非负数,他的下标代表该元素的双亲结点

若继续合并,分成了如下两个小团体,数组变化如下:

 


二、并查集可以解决哪些问题?

通过以上栗子,可以发现,并查集可以解决以下问题:

1.查找元素属于哪个集合

方法:通过树一直找到根,也就是数组中的负数

2.查看两个元素是否属于同一个集合

方法:通过树一直找到根,若根相同说明是同一集合;

3.将两个集合合并成一个集合

方法:将一个集合名称改成另一个集合名称;

4.求集合个数

方法:数组中元素为负数是当前下标集合的个数;


三、并查集的模拟实现

3.1、并查集的定义

底层是一个数组,并且全部初始化为-1;

public class UnionFindSet {
    public int[] elem;

    public UnionFindSet(int n) {
        this.elem = new int[n];
        Arrays.fill(elem, -1);
    }
}

3.2、查询两个元素是否是同一个集合

这里实现很简单,只需要比较两个元素的根节点是否相同即可,那么就需要先找到两个根节点,可以通过一个循环进行查找,当查找到的元素小于0时,说明找到根节点了;

    /**
     * 查找数组 x下标是否是根节点
     * @param x
     * @return
     */
    public int findRoot(int x) {
        if(x < 0) {
            throw new IndexOutOfBoundsException("下表不合法,是负数");
        }
        while(elem[x] >= 0) {
            x = elem[x];
        }
        return x;
    }

    /**
     * 查询 x1 和 x2 是不是同一个集合
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1, int x2) {
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        return index1 == index2;//跟结点是否相同
    }

3.3、合并两个集合

这里首先需要找到需要合并的两个元素的根节点,只有根节点不同才能进行合并,怎么合并呢?就是修改两个值,元素一的值因该被修改为这两个元素的和(这是更新孩子的数量),元素二的值因该被修改为元素一的下标(这是跟新另一颗树的根结点)(这里也很简单,建议参照上面我画的图去对比);

    /**
     * 合并操作
     * @param x1
     * @param x2
     */
    public void union(int x1, int x2) throws Exception {
        //先找到 x1, x2 的根节点
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) {
            return;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

3.4、求集合个数

遍历数组,并用一个计数器记录负数的个数,就是集合的个数;

    /**
     * 集合个数
     * @return
     */
    public int getCount() {
        int count = 0;
        for(int x : elem) {
            if(x < 0) {
                count++;
            }
        }
        return count;
    }

3.5、并查集完整代码

import java.util.Arrays;

public class UnionFindSet {
    public int[] elem;

    public UnionFindSet(int n) {
        this.elem = new int[n];
        Arrays.fill(elem, -1);
    }

    /**
     * 查找数组 x下标是否是根节点
     * @param x
     * @return
     */
    public int findRoot(int x) {
        if(x < 0) {
            throw new IndexOutOfBoundsException("下表不合法,是负数");
        }
        while(elem[x] >= 0) {
            x = elem[x];
        }
        return x;
    }

    /**
     * 查询 x1 和 x2 是不是同一个集合
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1, int x2) {
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        return index1 == index2;//跟结点是否相同
    }

    /**
     * 合并操作
     * @param x1
     * @param x2
     */
    public void union(int x1, int x2) {
        //先找到 x1, x2 的根节点
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if(index1 == index2) {
            return;
        }
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }

    /**
     * 集合个数
     * @return
     */
    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();
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        UnionFindSet unionFindSet = new UnionFindSet(10);
        System.out.println("合并:0 和 6:");
        unionFindSet.union(0, 6);
        System.out.println("合并:0 和 7:");
        unionFindSet.union(0, 7);
        System.out.println("合并:0 和 8:");
        unionFindSet.union(0, 8);

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

        System.out.println("合并:8 和 1:");
        unionFindSet.union(8, 1);
        unionFindSet.print();
        System.out.println(unionFindSet.isSameUnionFindSet(6, 9));
        System.out.println(unionFindSet.isSameUnionFindSet(8, 2));
    }
}

小结

面试考的少,自行斟酌~


 

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

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

相关文章

九、MySQL 常用函数汇总(2)

文章目录一、条件判断函数1.1 IF(expr,v1,v2)函数1.2 IFNULL(v1,v2)函数1.3 CASE函数二、系统信息函数2.1 获取MySQL版本号、连接数和数据库名的函数2.2 获取用户名的函数2.3 获取字符串的字符集和排序方式的函数2.4 获取最后一个自动生成的ID值的函数三、加密函数3.1 加密函数…

东宝商城项目(三)——用户注册功能的实现(后端)

本文是我做项目过程中记录的学习笔记&#xff0c;用于记录项目开发流程&#xff0c;第一次做项目有很多不懂的地方&#xff0c;本文可读性暂时很差。 我目前的学习目标是走完项目开发流程&#xff0c;知道独立开发一个项目并让项目上线需要经历哪些步骤&#xff0c;需要学到哪些…

java.util.ConcurrentModificationException: null异常

创作背景&#xff1a;在加强for循环中使用了remove操作 原因&#xff1a; 在官方文档中ConcurrentModificationException的介绍如下&#xff1a; public class ConcurrentModificationException extends RuntimeException 某个线程在 Collection 上进行遍历时&#xff0c;通…

Spring入门-IOC/DI注解管理与整合mybatis及Junit(2)

1&#xff0c;核心容器 前面已经完成bean与依赖注入的相关知识学习&#xff0c;接下来我们主要学习的是IOC容器中的核心容器。 这里所说的核心容器&#xff0c;大家可以把它简单的理解为ApplicationContext&#xff0c;前面虽然已经用到过&#xff0c;但是并没有系统的学习&a…

1.15日报

完成font.css global.css login.vue request.js 今天完成了前端与后端的联通&#xff0c;并成功响应请求。返回登录成功欣喜。 遇到的问题&#xff1a; 我的body设置了&#xff1a; margin:0; padding:0; 但是页面四周还有白色留边。原因&#xff1a;body设置无边框了&a…

用Scipy理解Gamma函数

文章目录Gamma函数对数Gamma函数复数域的Gamma函数Gamma函数 Γ\GammaΓ函数是阶乘的解析延拓&#xff0c;在概率论中非常常见&#xff0c;例如Gamma分布表示某个事件在某个时刻发生第nnn次的概率&#xff1a;Gamma分布详解 Γ\GammaΓ函数显含在Γ\GammaΓ分布中&#xff0c;其…

linux基本功系列之pwd命令实战

本文目录 文章目录一. pwd命令介绍二. 语法格式及常用选项2.1 语法格式2.2 常用参数三. 参考案例3.1 显示所在目录的完整路径3.2 显示符号链接的路径 -P 参数3.3 查看上一次所在的工作目录3.4 查看PWD的版本四. pwd的命令类型总结前言&#x1f680;&#x1f680;&#x1f680; …

7、redis数据库jedis省份缓存案例

Redis 1. 概念&#xff1a; redis是一款高性能的NOSQL系列的非关系型数据库 1.1.什么是NOSQL NoSQL(NoSQL Not Only SQL)&#xff0c;意即“不仅仅是SQL”&#xff0c;是一项全新的数据库理念&#xff0c;泛指非关系型的数据库。 随着互联网web2.0网站的兴起…

IO流练习(三)

1.编程题 Homework01.java (1)在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp (2)在e:\\mytemp目录下&#xff0c;创建文件hello.txt (3)如果hello.txt已经存在&#xff0c;提示该文件已经存在&#xff0c;就不要再重复创建了。 &#xff08;4&#xff09;并且在hello.tx…

Java加解密(八)数字证书

目录数字证书1 定义2 证书组成结构3 公钥基础设施&#xff08;PKI&#xff09;3.1 PKI的组成3.2 PKI的相关标准3.3 信任模型4 证书的应用场景5 证书链6 生成证书6.1 通过CA生成可信证书6.1.1 国际权威认证机构6.1.2 生成CSR6.1.2.1 使用XCA生成CSR6.1.2.2 使用OpenSSL生成CSR6.…

每日一题-力扣(leetcode)2059. 转化数字的最小运算数

传送门 题目描述 给你一个下标从 0 开始的整数数组 nums &#xff0c;该数组由 互不相同 的数字组成。另给你两个整数 start 和 goal 。 整数 x 的值最开始设为 start &#xff0c;你打算执行一些运算使 x 转化为 goal 。你可以对数字 x 重复执行下述运算&#xff1a; 如果…

AtCoder Beginner Contest 284解题报告(A-D)

A - Sequence of Strings Problem Statement You are given N strings S1​,S2​,…,SN​ in this order. Print SN​,SN−1​,…,S1​ in this order. Constraints 1≤N≤10N is an integer.Si​ is a string of length between 1 and 10, inclusive, consisting of lowe…

【Redis】Redis实现分布式锁

【Redis】Redis实现分布式锁 文章目录【Redis】Redis实现分布式锁1. 分布式锁概念2. 为什么要实现分布式锁2.1 并发安全问题3. 分布式锁的实现方案3.1 Redis实现分布式锁3.1.1 定义分布锁接口和类3.1.2 编写lua脚本3.1.3 使用线程锁3.1.4 总结在实现分布式锁之前&#xff0c;首…

aardio - 升级bindConfig函数,支持多属性和多子组件

一、需求分析 aardio的 winform.bindConfig() 函数&#xff0c;绑定后&#xff0c;一个组件&#xff0c;只能保存一个属性。 有时候需要同时保存多个属性&#xff0c;比如一个comobox组件&#xff0c;需要保存项目列表&#xff0c;同时保存当前选中的项目索引。当前这个bindC…

代码随想录算法训练营第十八天二叉树 java : .106 从中序与后序遍历序列构造二叉树113. 路径总和ii 112 路径总和 513.找树左下角的值

文章目录前言LeetCode 513.找树左下角的值题目讲解思路那么如何找最左边的呢&#xff1f;Leetcode 112 路径总和题目讲解LeetCode 113. 路径总和ii题目讲解Leetcode 106 从中序与后序遍历序列构造二叉树题目讲解前言 人的不幸在于他们不想走自己的那条路&#xff0c;总想走别人…

大数据必学Java基础(一百二十四):Maven的常见插件

文章目录 Maven的常见插件 一、编辑器插件 二、资源拷贝插件 三、tomcat插件 Maven的常见插件

Dubbo 服务暴露

Dubbo 服务暴露 1. 服务暴露时序图 2. 源码分析 DubboBootstrap.exportServices 从配置管理器中获取到所有的ServiceConfig实例&#xff0c;遍历&#xff0c;然后一个一个的暴露。 ServiceConfig.export 如果DubboBootstrap为空&#xff0c;也就没有初始化&#xff0c;就初…

猴子都能看懂的噪声(noise)专题

背景 除了生成各种奇形怪状与自然景观&#xff0c;噪声也有其他美妙的用途&#xff01; 工作原因&#xff0c;经常接触与噪声相关的画面效果&#xff08;火焰啊&#xff0c;画面扰动啊之类的&#xff09;&#xff0c;做的时候一知半解&#xff0c;傻傻分不清楚各种形态的nois…

Java文件:XWPFDocument导出Word文档

文章目录一、前言二、基本的概念三、Maven依赖(JAR)四、Word模板1.正文段落2.正文表格3.页眉4.页脚五、XWPFDocument的使用5.4导出Word文档1.word模板2.PdfTest测试类3.ISystemFileService接口4.SystemFileServiceImpl实现类5.结果六、遇到问题5.1输出为word的时候换行符无效一…

NR5G基础概念扫盲

文章目录前言BWP未完待续前言 随着人工智能、万物互联时代的到来&#xff0c;人类社会进入到一个新的阶段。新兴的科技产业对信息社会基础设施提出了更高的要求&#xff0c;对低时延、大带宽、高流量的需求&#xff0c;催生了5G技术&#xff0c;并推动其蓬勃发展。通信&#x…