图论02-并查集的实现(Java)

2.并查集理论基础

  • 并查集的作用
java 复制代码
将两个元素添加到一个集合中。
判断两个元素在不在同一个集合
  • 并查集的实现
java 复制代码
1.DSU 类定义:DSU 类中包含一个整型数组 s 用来存储元素的父节点信息。

2.DSU 构造函数:
构造函数 DSU(int size) 接受一个参数 size,初始化了大小为 size 的并查集。
在构造函数中,数组 s 被初始化为一个大小为 size 的数组,初始时每个节点的父节点是自己。
find 方法:

3.find(int x) 方法用于查找元素 x 所在集合的根节点(即代表元素)。
如果 x 的父节点等于自己,则说明 x 就是根节点,直接返回 x。
否则递归调用 find 方法,找到 x 的父节点的根节点并返回。

4.union 方法:
union(int x, int y) 方法用于合并元素 x 和元素 y 所在的两个集合。
在该实现中,直接将 x 的父节点设置为 y,即将 x 所在集合的根节点指向 y 所在集合的根节点。

Java代码实现

java 复制代码
public class DSU {
    int[] s;

    /**
     * 初始化并查集,指定大小,并将每个元素初始化为自己的父节点。
     * @param size 并查集的大小。
     */
    public DSU(int size) {
        s = new int[size];
        for (int i = 0; i < s.length; i++) {
            s[i] = i;
        }
    }

    /**
     * 查找操作,用于查找包含元素 x 的集合的根/父节点。
     * @param x 要查找的元素。
     * @return 包含 x 的集合的根节点。
     */
    public int find(int x) {
        if (x == s[x]) {
            return x;
        }
        return find(s[x]);
    }

    /**
     * 合并操作,用于合并包含元素 x 和 y 的集合。
     * @param x 第一个元素。
     * @param y 第二个元素。
     */
    public void union(int x, int y) {
        s[x] = y;
    }
}
java 复制代码
x = set.find(2);//找2节点的代表节点
y = set.find(3);//找3节点的代表节点
if (x != y) {//当二者没有相同的代表节点表明二者不在同一个集合之中,可以连接
	set.union(x, y);
}
  • 路径压缩
java 复制代码
原因:在普通的并查集中,通过不断向上查找父节点的方式找到根节点,这可能导致树的深度较大,从而影响查找操作的效率。路径压缩通过在查找时将节点直接连接到根节点,减少了树的深度,提高了查找操作的效率。
java 复制代码
方法:我们可以在查找父节点的时候,我们通过向上查找便可以知道谁是自己的父节点,相比直接返回父节点,我们可以顺便将自己指向父节点,这样可以降低树的深度
public int find(int x) {
        if (x == s[x]) {
            return x;
        }
        return s[x] = find(s[x]);
    }
  • 优化后完整代码
java 复制代码
DSU(int size) 构造函数:初始化并查集,创建了两个数组 s 和 size,分别用来存储集合中各点的关系和判断不同集合的大小。在初始化过程中,将每个节点的值初始化为索引的值,表示每个节点最初都是一个独立的集合,大小为1。

find(int x) 方法:查找元素 x 的根节点。通过递归地查找 x 的父节点,直到找到根节点为止。在查找的过程中,进行路径压缩操作,将沿途经过的节点直接指向根节点,从而降低树的深度,优化后续查找操作的效率。

union(int x, int y) 方法:合并两个集合。在合并操作中,首先根据两个集合的大小判断,让元素较少的集合指向元素较多的集合,以减小树的深度。然后更新集合的大小信息,确保合并后大集合的大小正确反映合并前两个集合的大小之和。
java 复制代码
public class DSU {
    int[] s;//用来存储集合中各点的关系
    int[] size;//用来判断不同集合的大小

    public DSU(int size) {//初始化并查集
        s = new int[size];
        this.size = new int[size];
        for (int i = 0; i < s.length; i++) {
            s[i] = i;//将每个节点的值初始化为索引的值
            this.size[i] = 1;//此时每个索引代表一个集合,因此集合数目为1
        }
    }

    public int find(int x) {//查找元素x的根节点
        if (x == s[x]) {//如果节点的索引与节点的值一样,说明找到节点
            return x;
        }
        //如果不相等,根据值去找根节点,因为值记录的是根节点的位置
        //路径压缩:寻找根节点的难度会随着树的深度而不断增大,所以若找到根节点,直接将根节点的值赋值给x索引的值,从而降低树的深度
        return s[x] = find(s[x]);
    }

    public void union(int x, int y) {//合并两个集合
        //在进行查找根节点的时候,会从一个节点的值不断寻找
        //对于一个集合数目大的元素,查找起来更加费时,如果
        //让大的集合指向小的集合,会使树的深度再次增加,加大
        //复杂度,因此我们需要判断连个集合的大小,让小集合指向大集合
        if (size[x] < size[y]) {//判断集合的大小
            int temp = y;
            y = x;
            x = temp;
        }
        //x表示大集合,y表示小集合
        s[y] = x;//y集合的父节点为x
        size[x] = size[x] + size[y];//此时大集合的大小为原大集合的大小加小集合的大小
    }

    @Override
    public String toString() {
        return Arrays.toString(s);
    }
}
相关推荐
SimonKing34 分钟前
无需重启!动态修改日志级别的神技,运维开发都哭了
java·后端·程序员
杨杨杨大侠1 小时前
第3篇:配置管理的艺术 - 让框架更灵活
java·spring·log4j
WCL-JAVA2 小时前
java生成带水印的pdf文件
java·python·pdf
pengzhuofan2 小时前
Java设计模式-模板方法模式
java·设计模式·模板方法模式
Java中文社群2 小时前
重磅!Ollama发布UI界面,告别命令窗口!
java·人工智能·后端
YuTaoShao2 小时前
【LeetCode 热题 100】152. 乘积最大子数组——(解法一)递推
java·算法·leetcode·职场和发展
熙客2 小时前
Java:HashMap的使用
java·开发语言
程序员清风2 小时前
程序员代码有Bug别怕,人生亦是如此!
java·后端·面试
就是帅我不改2 小时前
告别996!高可用低耦合架构揭秘:SpringBoot + RabbitMQ 让订单系统不再崩
java·后端·面试
hhzz3 小时前
Maven项目中settings.xml终极优化指南
java·jdk·maven