【数据结构进阶】并查集

本文介绍了并查集这一数据结构,它用于集合的合并与查询。阐述了其原理,由整型数组和两个函数构成,还说明了现实意义。接着讲解了并查集的实现,底层是初始值为 -1 的数组。最后介绍了其在省份数量、等式方程可满足性等问题上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

并查集

正如它的名字一样,并查集(Union-Find)就是用来对集合进行 合并(Union)查询(Find) 操作的一种数据结构。
合并 就是将两个不相交的集合合并成一个集合。
查询 就是查询两个元素是否属于同一集合。

并查集的原理

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

组成

并查集主要由一个整型数组pre[ ]和两个函数find( )、join( )构成。

数组 pre[ ] 记录了每个点的前驱节点是谁,函数 find(x) 用于查找指定节点 x 属于哪个集合,函数 join(x,y) 用于合并两个节点 x 和 y 。

现实意义

比如现在有这样的情况:

目前饭局有10个人,没两个人之间都可能存在远方亲戚关系,如何将个人分成不同的家庭?现在将个人编号为{0,1,2,3,4,5,6,7,8,9}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xp2EqcYB-1672971490156)(C:\Users\17512\AppData\Roaming\Typora\typora-user-images\1672967653754.png)]

-1表示假设每个人之间都不存在亲戚关系

接下来,饭局中的人互相交谈,了解到自己的亲戚关系,因此可以形成不同的家庭。比如:当前是s1:{0,6,7,8},s2:{1,4,9},s3:{2,3,5}形成了不同的家庭。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VZrorsUR-1672971490158)(C:\Users\17512\AppData\Roaming\Typora\typora-user-images\1672967711197.png)]

用树模型表示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8NEgt0JH-1672971490159)(C:\Users\17512\AppData\Roaming\Typora\typora-user-images\1672967778007.png)]

因此规定并查集数组有下面的规定:

  1. 数组的下标对应集合中元素的编号
  2. 数组中如果为负数,负号代表根,数字代表该集合中元素个数
  3. 数组中如果为非负数,代表该元素双亲在数组中的下标
  4. 如果此时0和1发现也有亲戚关系,那么s1和s2可以合并为一个新的家庭

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-04KJOESp-1672971490160)(C:\Users\17512\AppData\Roaming\Typora\typora-user-images\1672967818968.png)]

并查集需要有下面的接口

  • 查找元素属于哪个集合
  • 查看两个元素是否属于一个集合
  • 合并两个集合
  • 集合的个数

并查集的实现

创建一个并查集

并查集底层就是一个数组,数组内每个元素初始为-1。

public class unionfindset {
   
   
    public int[] elem;
    public int usedSize;

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

    public static void main(String[] args) {
   
   
        unionfindset unionfindset = new unionfindset(10);
        System.out.println(123);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1R8vPpbF-1672971490160)(C:\Users\17512\AppData\Roaming\Typora\typora-user-images\1672968167815.png)]

功能实现:

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

    /**
     * 查询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;
        }else{
   
   
            return false;
        }
    }
 /**
  
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙宇航的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值