并查集

查集就是维护了几个动态的集合,集合中的每一个元素都标记了一个父节点,同一个集合的代表是相同的。当一个元素的父节点就是他本身时,它就是该集合的代表。

并查集有三种操作:

1. init(n):用于初始化集合,将每个元素的父节点设置为他本身。即表示当前一个元素为一个集合,互相没有联系

2. find(x):返回x所在集合的代表

3. unite(x,y):合并x,和y所在的集合。即把y的代表设置为x所在集合的代表

根据并查集判断两个元素是否有联系,只需判断他们是否在同一个集合里即可,也就是判断他们的代表是不是同一个

>>初始化

// 初始化n个元素
void init(int n)
{
    for (int i = 1; i <= n; i++) {
        par[i] = i;
        rank[i] = 0;
    }
}

>>查询

//递归实现 
int find(int x) 
{  
    if (par[x]!=x) return find(par[x]);  
    else return x;
    //或者用return x == father[x] ? x: father[x] = find(father[x]);
}

//非递归路径压缩操作
int find(int x)
{
    int r = x;
    while(r!=par[r]) r = par[r];
    //路径压缩
    int i = x, j;        
    while(i!=r) {   
        j = par[i];   //用j暂存par[i]的父节点
        par[i] = r;   //par[i]指向根节点
        i = j;        //i移到父节点
    }
    return r;           
}

>>合并

//合并x和y所在的集合
void unite(int x, int y)
{
    x = find(x);
    y = find(y); //将x和y的根分别赋值给x和y
    if (x==y) return; //如果x于y的根相同,则不必合并
 
    if (rank[x]<rank[y]) //合并时如果两棵树的高度不同,则将rank小的连到rank到的上面
        par[x] = y;
    else {
        par[y] = x;
        if (rank[x]==rank[y]) rank[x]++; //如果相同,则最高的高度合并之后需要在原来的基础上+1
    }
}

 参考自:

https://www.cnblogs.com/frankM/p/4399556.html

https://www.cnblogs.com/52dxer/p/10470004.html

https://www.cnblogs.com/sr1993/p/3697783.html

http://www.cnblogs.com/tanhehe/archive/2013/01/28/2883506.html

https://blog.csdn.net/zchahaha/article/details/51123557

原文地址:https://www.cnblogs.com/wizarderror/p/10752791.html