关于并查集的一些个人总结

一、什么是并查集?

并查集是一种数据结构,通常用来判断元素之间是否属于同一个集合。在LeetCode200.岛屿数量中就可以使用并查集解决。

二、基本思路

使用数组存储每个元素所在的集合。例如union[2] == 1,代表第三个元素是集合1里的元素。

1、初始化

使用并查集,首先对并查集进行初始化,代码示例如下:

private int[] union;

private int size;

public void initUnion(){
    union = new int[size];
    for(int i = 0; i < size; i++){
        union[i] = i;
    }
}

2、查找元素属于哪个集合

public int find(int element){
    return union[element];
}

3、判断两个元素是否属于同一个集合

public boolean isConnected(int element1,int element2){
    return find(element1) == find(element2);
}

4、合并两个元素所在的集合

public void unionElements(int element1,int element2){
    int set1 = find(element1);
    int set2 = find(element2);
    //如果两个集合不同就合并
    if(set1 != set2){
        for(int i = 0; i < size; i++){
            if(find(i) == set1){
                union[i] = set2;
            }
        }
    }
}

三、对基础并查集的优化

1、快速union

基础的并查集的union过程时间复杂度是O(N),每一次合并都需要遍历全部元素。

改进:union中保存的是每个元素的父亲编号。例如:union[1] == 3,union[3] == 6,union[6] == 6

即元素1是和3一个集合的,而元素3和元素6是一个集合的,元素6集合的代表元素就是他自己。所以,元素1、3、6都属于一个集合。

现在要合并集合怎么办呢?让最大的父亲编号变成新的代表元素即可。

public class Union{
    
    private int[] parent;
    private int size;
    
    //初始化并查集
    public void initUnion(int size){
        this.size = size
        parent = new int[size];
        for(int i = 0; i < size; i++){
            parent[i] = i;
        }
    }

    //查找代表元素
    public int find(int element){
        while(element != parent[element]){
            element = parent[element];
        }
        return element;
    }

    //是否属于同一个集合
    public boolean isConnected(int element1,int element2){
        return find(element1) == find(element2);
    }

    //合并
    public void union(int element1,int element2){
        int set1 = find(element1);
        int set2 = find(element2);
        if(set1 == set2) return;
        parent[set1] = set2;
    }
}

2、如何决定谁合并到谁的集合里呢?

1)按重量合并

即谁下面的元素多,谁就是新的大集合的老大。

对于集合新加一个数组weight[],用来存储集合中元素的个数。

在union操作时,谁的集合大,就用谁当代表元素,同时,weight[element]要加上另一个集合的weight。

2)按深度合并

如果按重量合并,合并到一定程度后,集合就像链表一样成线性的了,find()的时间复杂度就会趋近于O(N)。

新增加一个数组height[],用来记录集合的深度。

所以,可以按深度合并,谁的深度高,就以谁为老大,这样集合的最大深度就不会改变。

3、路径压缩

路径压缩的目的是为了处理深度较大的元素。

处理方式很简单,在find()中,将深度大的元素的parent指向自己父亲的父亲

parent[element] = parent[parent[element]];

这样就减小了深度。

一般只在基于重量的并查集中使用,因为高度的减小并不会影响重量,而高度重新计算很麻烦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值