[笔记] 并查集

· · 算法·理论

1, 什么是并查集

并查集是一种很简洁的数据结构,主要作用于元素分类的问题,它存放了一堆一堆的不相交的集合,并可对其进行创建、查询和合并三种操作。

并查集最核心的思想在于用集合中的祖先元素来代表整个集合。

2, 合并优化

① 按轶合并


优化代码:

int find(int x){                    //前置函数,用于寻找一个节点的祖宗节点
    if(f[x] == x) return x;
    else return find(f[x]);
}
void merge(int x, int y){           //merge(x, y)表示将x, y的祖宗节点按轶合并 
    int rx = find(x), ry = find(y);
    if(rx == ry) return;
    if(deep[rx] <= deep[ry]){
        f[rx] = ry;
    }else if(deep[rx] > deep[ry]){
        f[ry] = rx;
    }
    if(deep[rx] == deep[ry]){
        deep[ry]++;
    }
    return; 
}

②路径压缩


优化代码:

int find(int x){
    if(x == f[x]) return x;
    else return f[x] = find(f[x]);
}

③路径压缩+按轶合并

书接上回,那么路径压缩后每一个集合是否都是两层呢? NO!
路径压缩是在find函数里进行的,只能压缩当前查询的路径,所以我们可以把二者结合起来。
优化代码:

int find(int x){                    //前置函数,用于寻找一个节点的祖宗节点
    if(f[x] == x) return x;
    else return f[x] = find(f[x]);  //路径压缩
}
void merge(int x, int y){           //按轶合并 
    int rx = find(x), ry = find(y);
    if(rx == ry) return;
    if(deep[rx] <= deep[ry]){
        f[rx] = ry;
    }else if(deep[rx] > deep[ry]){
        f[ry] = rx;
    }
    if(deep[rx] == deep[ry]){
        deep[ry]++;
    }
    return; 
}

3, 最终代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int f[MAXN], deep[MAXN];
void init(int n){
    for (int i = 1; i <= n; i++){
        f[i] = i;
    }
}
int find(int x){
    if(f[x] == x) return x;
    else return f[x] = find(f[x]);
}
void merge(int x, int y){
    int rx = find(x), ry = find(y);
    if(rx == ry) return;
    if(deep[rx] <= deep[ry]){
        f[rx] = ry;
    }else if(deep[rx] > deep[ry]){
        f[ry] = rx;
    }
    if(deep[rx] == deep[ry]){
        deep[ry]++;
    }
    return;
}
bool is_contact(int x, int y){
    if(find(x) == find(y)) return 1;
    else return 0;
}
int main(){

    return 0;
}