并查集

文章目录


一、并查集是什么?

        并查集是一种用于处理集合合并与查询的数据结构。它用于解决一些与集合划分相关的问题,例如连通性、等价关系等。当我们需要判断两个元素是否在同一个集合里的时候,我们就要想到用并查集。

二、功能

1.将两个元素添加到一个集合中。

2.判断两个元素在不在同一个集合

三、基本原理

        每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个结点存储它的父结点,father[x]表示x的父结点。

四、代码实现

        假设我们将三个元素A,B,C (分别是数字)放在同一个集合,其实就是将三个元素连通在一起,如何连通呢。

        只需要用一个一维数组来表示,即:father[A] = B,father[B] = C 这样就表述 A 与 B 与 C连通了(有向连通图)。

// 将v,u 这条边加入并查集
void add(int u, int v) {
    u = find(u); // 寻找u的根
    v = find(v); // 寻找v的根
    if (u == v) return; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
    father[v] = u;
}
//比如说去连通A和B,先去寻找A、B的根,如果两个的根相同,说明在一个集合中,不需要进行操作.
//如果不相同,即father[find(A)] = find(B),也就是合并A、B所在的两个集合

只要 A ,B,C 在同一个根下就是同一个集合。

给出A元素,就可以通过 father[A] = B,father[B] = C,找到根为 C。

给出B元素,就可以通过 father[B] = C,找到根也为为 C,说明 A 和 B 是在同一个集合里。 

// 返回x的祖宗节点
int find(int x){
	if (father[x] != x) father[x] = find(father[x]);
	return father[x];
}
//在实现 find 函数的过程中,我们知道,通过递归的方式,不断获取father数组下标对应的数值,最终找到这个集合的根。
//搜索过程像是一个多叉树中从叶子到根节点的过程。如果这棵多叉树高度很深的话,每次find函数去寻找根的过程就要递归很多次。
//我们的目的只需要知道这些节点在同一个根下就可以,所以我们要进行路径压缩,我们只需要在递归的过程中,让 father[u] 接住 递归函数 find(father[u]) 的返回结果
//因为 find 函数向上寻找根节点,father[u] 表述 u 的父节点,那么让 father[u] 直接获取 find函数 返回的根节点,这样就让节点 u 的父节点 变成根节点。

如果要判断两个元素是否在同一个集合里,可以通过 find函数寻根,如果属于同一个根的话,那么这两个元素就是在同一个集合。

如何表示 C 也在同一个元素里呢? 我们需要 father[C] = C,即C的根也为C,这样就方便表示 A,B,C 都在同一个集合里了。所以我们要进行初始化。

// 并查集初始化
for (int i = 0; i < n; i ++ ) father[i] = i;


五、相关题目

力扣.684. 冗余连接

树可以看成是一个连通且 无环 的 无向 图。

给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。

请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的那个。

解答:

//我们可以从前向后遍历每一条边,边的两个节点如果不在同一个集合,就加入集合。
class Solution {
    int[] father;
    int find(int x){
        if(father[x]!=x) father[x]=find(father[x]);
        return father[x];
    }
    public int[] findRedundantConnection(int[][] edges) {
        int n=edges.length;
        father=new int[n+1];
        //初始化
        for(int i=1;i<=n;i++) father[i]=i;
        //遍历
        for(int i=0;i<=n-1;i++){
            int u=find(edges[i][0]);
            int v=find(edges[i][1]);
           //如果u==v说明有相同的根结点,说明已经连在一起了
            if(u==v) return edges[i];
            father[v]=u;
        }
        return new int[]{};
    }
}

参考:代码随想录、acwing

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@zh-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值