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

本文详细介绍了并查集理论基础,包括其作用、实现方法(DSU类中的find和union操作),以及路径压缩的原理和优化后的Java代码示例。通过优化查找过程,提高并查集的效率。
摘要由CSDN通过智能技术生成

2.并查集理论基础

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

image-20240314110232088

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代码实现

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

union(int x, int y) 方法:合并两个集合。在合并操作中,首先根据两个集合的大小判断,让元素较少的集合指向元素较多的集合,以减小树的深度。然后更新集合的大小信息,确保合并后大集合的大小正确反映合并前两个集合的大小之和。
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);
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 并查集是一种常用的数据结构,用于解决联通性问题,通常应用于图论中。以下是一个使用Java实现查集的示例。 假设我们有一个由10个节点构成的图,节点编号分别为0-9。现在我们需要将这10个节点分成3个集合,其中第一个集合包括节点0,1,2,第二个集合包括节点3,4,5,第三个集合包括节点6,7,8,9。我们可以使用并查集实现这个目标。 下面是使用Java实现查集的示例代码: ```java public class UnionFind { int[] parent; public UnionFind(int n) { parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } public int find(int x) { if (parent[x] == x) { return x; } return parent[x] = find(parent[x]); } public void union(int x, int y) { int px = find(x); int py = find(y); parent[px] = py; } public static void main(String[] args) { UnionFind uf = new UnionFind(10); uf.union(0, 1); uf.union(1, 2); uf.union(3, 4); uf.union(4, 5); uf.union(6, 7); uf.union(7, 8); uf.union(8, 9); System.out.println(uf.find(0) == uf.find(2)); System.out.println(uf.find(3) == uf.find(5)); System.out.println(uf.find(6) == uf.find(9)); } } ``` 这个示例中,我们首先创建一个长度为10的并查集,表示有10个节点。然后我们调用`union()`方法将节点分成3个集合。最后,我们可以使用`find()`方法查询两个节点是否在同一个集合中。 运行这个示例代码,可以看到输出结果为: ``` true true true ``` 这说明节点0、1、2在同一个集合中,节点3、4、5在同一个集合中,节点6、7、8、9在同一个集合中,符合我们的预期。 ### 回答2: 并查集是一种用于处理元素分组和查找的数据结构。在JAVA中,可以使用数组和指针实现一个并查集。 举个例子来说明,假设有5个元素{1, 2, 3, 4, 5},初始时每个元素都是独立的组,即每个元素是一个独立的集合。下面以操作序列为例,演示并查集的使用。 1. 初始化并查集,分别给每个元素设置一个集合代表元素。 假设初始时集合代表元素为{1, 2, 3, 4, 5}。 2. 根据需求进行合并操作,将元素合并到同一个组中。 假设合并操作为(1, 2),即将元素1和元素2合并到同一个组中。此时集合代表元素为{1, 2, 3, 4, 5},但元素1和元素2在同一个组。 3. 再进行合并操作,合并元素3和元素4到同一个组中。 合并操作为(3, 4),此时集合代表元素为{1, 2, 3, 3, 5},元素3和元素4在同一个组。 4. 进行查找操作,判断两个元素是否在同一个组。 查找操作为(2, 4),根据之前的合并操作,元素2和元素4应该在同一个组中。结果为true。 5. 再进行查找操作,判断元素1和元素5是否在同一个组。 查找操作为(1, 5),元素1和元素5没有进行过合并操作,所以不在同一个组中。结果为false。 通过以上例子可以看出,并查集可以快速判断两个元素是否在同一个组中,以及合并两个元素到同一个组中。并查集图论、网络连通性等问题中有广泛应用。 ### 回答3: JAVA查集是一种用于处理不相交集合合并与查询问题的数据结构。它主要涉及两个基本操作:合并和查找。 举个例子来说明并查集的使用。假设有一个朋友圈的关系网,我们需要根据人们的好友关系构建一个并查集。 我们可以创建一个Person类来表示每个人,其中包含两个属性:id和parent。 ```java class Person { int id; int parent; public Person(int id) { this.id = id; this.parent = id; // 初始化时每个人的父节点都是自己 } } ``` 然后我们创建一个并查集类,并实现合并和查找操作。 ```java class UnionFind { Person[] people; public UnionFind(int n) { people = new Person[n]; for (int i = 0; i < n; i++) { people[i] = new Person(i); } } public int find(int x) { if (people[x].parent != x) { people[x].parent = find(people[x].parent); // 路径压缩 } return people[x].parent; } public void union(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { people[rootX].parent = rootY; // 合并两个集合 } } } ``` 接下来,我们可以使用并查集来处理好友关系,并查找某两个人是否属于同一个朋友圈。 ```java public class Main { public static void main(String[] args) { int n = 5; // 总共有5个人 UnionFind uf = new UnionFind(n); uf.union(0, 2); // 将人0和人2合并到同一个朋友圈 uf.union(1, 3); // 将人1和人3合并到同一个朋友圈 System.out.println(uf.find(0) == uf.find(2)); // 输出true,说明人0和人2属于同一个朋友圈 System.out.println(uf.find(1) == uf.find(4)); // 输出false,说明人1和人4不属于同一个朋友圈 } } ``` 通过以上示例,我们可以看出JAVA查集可以帮助我们快速并且高效地处理不相交集合合并与查询问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值