并查集

本文介绍了并查集这一数据结构及其在无向图中判断回路的应用。通过查找(find)和合并(union)操作,详细解析了find函数和union函数的工作原理。并通过实例展示了如何初始化、构建并查集数组trance,以及如何根据find和union判断无向图中是否存在回路,避免形成环状结构。最后,提供了一段完整的Java代码实现。
摘要由CSDN通过智能技术生成

一、并查集的操作

1、查找(find):确定元素属于哪个集合

2、合并(union):将两个集合归并成一个集合

二、查找、合并操作代码

1、查找操作 代码

    public int find(int x, int[] find) {
        if (find[x] < 0)
            return x;
        else
            return find(find[x], find);
    }

2、合并操作 代码

    public void union(int root1, int root2, int[] find) {
        find[root1] = root2;
    }

三、 实例讲解#

1、准备工作

1、初始化

1、在无向图中存在几个顶点,就开辟一个长度为顶点数量大小的数组, 并初始化为 -1,数组记为 trance

2、find 函数的作用

1、 若此时 trance 数组为图示状态,先不用计较该数组是如何得到的,只需要知道 find 函数的执行流程,下边会介绍如何构建 trance 数组

*2、*find 函数的执行过程

对 3 调用 find 函数

搜索 trance[3],
由于 trance[3] = 2,
搜索 trance[2],
由于 trance[2] = 1,
搜索 trance[1],
由于 trance[1] = 0,
搜索 trance[0],
由于 trance[0] = -1,
此时返回 0

对 5 调用 find 函数

搜索 trance[5],
由于 trance[5] = 4,
搜索 trance[4],
由于 trance[4] = 1,
此时返回 4

这就是整个 find 的函数的执行流程

2、union 函数的作用

union 函数非常简单,传入两个参数 root1, root2

让第一个参数作为数组 trance 的下标,让第二个参数作为第一个参数对应下标的值
例如 root1 = 3, root2 = 5
则有 trance[3] = 5

例如 例如 root1 = 0, root2 = 2
则 trance[0] = 2

3、如何判断是否存在回路

存在一条边 side,该边有两个顶点 a,b(find 函数的详细过程请看上面 2、find 函数的作用)

使用 a 调用 find 函数返回 num1 >= 0
使用 b 调用 find 函数返回 num2 >= 0
当 num1 与 num2 相等时,证明若把 side 边纳入到 trance 数组中时,
会出现回路,因此此时不要将 side 边纳入到 trance 数组中

示例:

此时 trance 数组为图示状态,先不用计较该数组是如何得到的,

只需要知道如何判断回路就可以,下边会介绍如何构建 trance 数组

存在一条边 side,该边有两个顶点 3,5

使用 2 调用 find 函数 trance[3] = 2
					 trance[2] = 1
					 trance[1] = 0
					 trance[0] = 4
					 trance[4] = -1
					 所以 num1 = 4 >= 0

使用 5 调用 find 函数 trance[5] = 4
					 trance[4] = -1
					 所以 num2 = 4 >= 0
					由于 num1 = num2,所以在该有无图中存在回路
					不会将边 side 纳入到 trance 数组中

2、使用并查集判断下图所示的无向图中是否存在回路

下面将通过实例讲解 trance 数组是如何构建的

1、初始化

由于在图示中存在 4 个顶点,所以初始化一个长度为 4 的数组,数组记为 trance,

并初始化为 -1

数组的初始状态如图所示

2、将边 a 纳入到 trance 数组

此时数组 trance 的状态如图

边 a 有 0, 1 顶点
对 0 调用 find 函数	tranc[0] = -1
					所以 num1 = 0 >= 0

对 1 调用 find 函数	tranc[1] = -1
					所以 num2 = 1 >= 0

此时使用 num1 和 num2 调用 union 函数 (这里可以看 2、union 函数的作用 上方黑体字部分)
					有 trance[0] = 1

2、将边 b 纳入到 trance 数组

此时数组 trance 的状态如图

边 b 有 0, 2 顶点
对 0 调用 find 函数	tranc[0] = 1
					tranc[1] = -1
					所以 num1 = 1 >= 0

对 2 调用 find 函数 tranc[2] = -1
					所以 num2 = 2 >= 0

此时使用 num1 和 num2 调用 union 函数
					有 trance[1] = 2

3、将边 c 纳入到 trance 数组

此时数组 trance 的状态如图

边 c 有 0, 3 顶点
对 0 调用 find 函数	tranc[0] = 1
					tranc[1] = 2
					trance[2] = -1
					所以 num1 = 2 >= 0

对 3 调用 find 函数 tranc[3] = -1
					所以 num2 = 3 >= 0

此时使用 num1 和 num2 调用 union 函数
					有 trance[2] = 3

4、将边 d 纳入到 trance 数组

此时数组 trance 的状态如图

边 d 有 1, 2 顶点
对 1 调用 find 函数	tranc[1] = 2
					tranc[2] = 3
					trance[3] = -1
					所以 num1 = 3 >= 0

对 2 调用 find 函数	tranc[2] = 3
					tranc[3] = -1
					所以 num2 = 3 >= 0

此时 num1 = num2 存在回路,就不向 trance 中纳入边 d,此时 trance 数组不发生变化

5、将边 e 纳入到 trance 数组

此时数组 trance 的状态如图

边 e 有 1, 3 顶点
对 1 调用 find 函数	tranc[1] = 2
					tranc[2] = 3
					trance[3] = -1
					所以 num1 = 3 >= 0

对 3 调用 find 函数	tranc[3] = -1
					所以 num2 = 3 >= 0

此时 num1 = num2 存在回路,就不向 trance 中纳入边 e,此时 trance 数组不发生变化

6、将边 f 纳入到 trance 数组

此时数组 trance 的状态如图

边 f 有 2, 3 顶点
对 2 调用 find 函数	tranc[2] = 3
					trance[3] = -1
					所以 num1 = 3 >= 0

对 3 调用 find 函数	tranc[3] = -1
					所以 num2 = 3 >= 0

此时 num1 = num2 存在回路,就不向 trance 中纳入边 e,此时 trance 数组不发生变化

四、完整代码

package other;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 并查集
 */
public class UnionFindSet {

    public static void main(String[] args) {
        UnionFindSet unionFindSet = new UnionFindSet();
        int[] trance = new int[4];
        List<String> list = new ArrayList<>();
        list.add("0-1");
        list.add("0-2");
        list.add("0-3");
        list.add("1-2");
        list.add("1-3");
        list.add("2-3");

        for (int i = 0; i < trance.length; i++) {
            trance[i] = -1;
        }

        for (String s : list) {
            System.out.println(Arrays.toString(trance));
            String[] split = s.split("-");
            int find1 = unionFindSet.find(Integer.parseInt(split[0]), trance);
            int find2 = unionFindSet.find(Integer.parseInt(split[1]), trance);
            if (find1 != find2) {
                unionFindSet.union(find1, find2, trance);
            }
        }
    }

    public int find(int x, int[] trance) {
        if (trance[x] < 0)
            return x;
        else
            return find(trance[x], trance);
    }

    public void union(int root1, int root2, int[] trance) {
        trance[root1] = root2;//将root1作为root2的新树根
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值