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

news/2024/7/15 18:54:08 标签: 图论, java

2.并查集理论基础

  • 并查集的作用
java">将两个元素添加到一个集合中。
判断两个元素在不在同一个集合
  • 并查集的实现

image-20240314110232088

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,分别用来存储集合中各点的关系和判断不同集合的大小。在初始化过程中,将每个节点的值初始化为索引的值,表示每个节点最初都是一个独立的集合,大小为1find(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);
    }
}

http://www.niftyadmin.cn/n/5440003.html

相关文章

Advice学习

简介 在Spring框架的AOP&#xff08;面向切面编程&#xff09;中&#xff0c;Advice接口是定义通知行为的抽象。然而&#xff0c;在Spring的实际实现中&#xff0c;Advice接口并没有直接被使用。相反&#xff0c;我们更常见的是MethodInterceptor接口、BeforeAdvice接口、Afte…

【Leetcode】1793. 好子数组的最大分数

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个整数数组 n u m s nums nums &#xff08;下标从 0 0 0 开始&#xff09;和一个整数 k k k 。 一个子数组 ( i , j ) (i, j) (i,j) 的 分数 定义为 m i n ( n u m s …

记录C++中,子类同名属性并不能完全覆盖父类属性的问题

问题代码&#xff1a; 首先看一段代码&#xff1a;很简单&#xff0c;就是BBB继承自AAA&#xff0c;然后BBB重写定义了同名属性&#xff0c;然后调用父类AAA的打印函数&#xff1a; #include <iostream> using namespace std;class AAA { public:AAA() {}~AAA() {}void …

81609A 步进可调谐激光源,大功率和低 SSE,基础型

这款激光源基于共同的腔体和激光模块设计&#xff0c;提供窄线宽和低自发射水平&#xff0c;与Keysight N774xA多端口功率计或Keysight 816xxx功率计模块配合使用时&#xff0c;能够在阻带和通带中实现出色的光谱损耗测量范围。81609A能够以0.1 pm的分辨率快速步进至离散波长&a…

1410. HTML 实体解析器

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 题目描述 「HTML 实体解析器」 是一种特殊的解析器&#xff0c;它将 HTML 代码作为输入&#xff0c;并…

计算机组成原理 第九章(控制单元的设计)—第三节(微程序设计(下))

写在前面&#xff1a; 本系列笔记主要以《计算机组成原理&#xff08;唐朔飞&#xff09;》为参考&#xff0c;大部分内容出于此书&#xff0c;笔者的工作主要是挑其重点展示&#xff0c;另外配合下方视频链接的教程展开思路&#xff0c;在笔记中一些比较难懂的地方加以自己的…

程序员下班以后做什么副业合适?

我就是一个最普通的网络安全工程师&#xff0c;出道快10年了&#xff0c;不出意外地遭遇到瓶颈期&#xff0c;但是凭技术在各大平台挖漏洞副业&#xff0c;硬是妥妥扛过来了。 因为对于程序员来讲&#xff0c;这是个试错成本很低、事半功倍的选择。编程技能是一种强大生产力&a…

vim | vim多标签之间的跳转

比如有两个标签&#xff1a; 按 Ctrl o 会直接跳转到上一次打开的文件&#xff0c;这样可能不够直观&#xff0c;可以用 :ls 进行查看buff&#xff0c;如下&#xff1a; 可以看到 %a 的是当前正在编辑的 # 是按 Ctrl o 会跳转到的 当然也可以用 这种命令进行跳转&#xff1…