【数据结构】并查集

并查集主要用于处理一些不相交集合的问题。

每个集合包含一个或多个元素,并且有一个代表元素。对于给定一个元素,可以快速找到其所属集合的代表元素,这样判断两个元素是否属于同一集合,只需要判断二者所属集合的代表元素是否一致即可。

如果要合并两个集合,只需要将其中一个集合的代表元素设为另一个集合的代表元素即可。

即,并查集主要应用于两个操作:

  1. 将两个集合合并
  2. 查询两个元素是否属于同一个集合

涉及到的主要操作有两个

  1. 合并:把两个元素所属集合合并(前提是两个集合不相交)
void join(int a, int b)
{
    int tmpa,tmpb;
    tmpa = find_root(a);
    tmpb = find_root(b);
    if(tmpa!=tmpb)
        root[tmpa] = tmpb;
}
  1. 查找根(代表元素):找到某一个元素的所属集合的根。
int find_root(int x)
{
    while(x!=root[x])
        x = root[x];
    return x;
}

//root[x]=y表示x的根是y,初始化时,每个元素的根都是自己

路径压缩*
查找根最坏的一种情况是一条常常的链,这时候查找的效率会大大降低,此时可以使用路径压缩,即将每个元素直接指向根节点 ,如下图。

我们可以在查找的过程中把每个元素的父节点直接设成根节点。

int find_root(int x)
{
    int root_of_x = x; //根节点
   
   // 找到x的根节点
    while(root_of_x != root[root_of_x])
        root_of_x = root[root_of_x];
    
    //将x到root_of_x路径上的每个节点的父节点都换成根节点x的根节点
    while(x != root[x]) 
    {
        int tmp = x;
        x = root[x];
        root[tmp] = root_of_x;
    }
    return root_of_x;
}