并查集

在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。

有一个联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作:

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
  • Union:将两个子集合并成同一个集合。

思路

开数组记录每个元素的从属情况,find 操作返回元素从属情况,union 操作修改其中一个元素的从属情况,将其合并

代码

最简单模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int set[1000];

void init(){
    for(int i<0;i<size;i++) set[i]=i;
}

int find(int x){
    return x==set[x]?x:find(set[x]);
}

int union(int x,int y){
    set[x] = y;
}

最简单的情况下没有任何优化,易退化成链状查询,查询复杂度到达$O(n)$

优化模板

添加路径压缩,减少查询时间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int Find(int x)//使用递归写 find 函数,同时有路径压缩
{
    int a;
    a=x;
    while(set[a]!=a)///循环方法查找前导点
    {
        a=set[a];
    }
    int i=x,j;
    while(i!=a)///路径压缩,修改历经的前导点
    {
        j=set[i];///记录 x 的前导结点
        set[i]=a;///将 i 的前导结点设置为 r 的根节点。
        i=j;
    }
    return a;

}

void Union(int x,int y)
{
    int a,b;
    a=Find(x);///x 的根节点为 a
    b=Find(y);///y 的根节点为 b
    if(a!=b)///如果 a,b 不是相同的根节点,则说明 ab 不是连通的
    {
        set[a]=b;///将 a,b 连接,将 a 的前导点设置为 b
    }
}

实例