并查集Union-Find Sets


什么是并查集?

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 进行快速规整。

并查集的主要操作

  1. 合并两个不相交集合
  2. 判断两个元素是否属于同一集合

主要操作的解释及代码

需要注意的是,一开始我们假设元素都是分别属于一个独立的集合里的。

(1)合并两个不相交集合 操作很简单:先设置一个数组Father[x],表示x的“父亲”的编号。那么,合并两个不相交集合的方法就是,找到其中一个集合最父亲的父亲(也就是最久远的祖先),将另外一个集合的最久远的祖先的父亲指向它。


a图为两个不相交集合,b图为合并后Father(b):=Father(g)

inline void union(int x, int y)

{

    // get_father 是下面将讲到的操作

   father[get_father(x)] = get_father(y); //指向最祖先的祖先

}

(2)判断两个元素是否属于同一集合 仍然使用上面的数组。则本操作即可转换为寻找两个元素的最久远祖先是否相同。可以采用递归实现。 (有待补图,制作中) 代码

inline char is_same(int x, int y)

{

    returnget_father(x) == get_father(y);

}

并查集的优化

(1)路径压缩

刚才我们说过,寻找祖先时采用递归,但是一旦元素一多起来,或退化成一条链,每次GetFather都将会使用O(n)的复杂度,这显然不是我们想要的。

对此,我们必须要进行路径压缩,即我们找到最久远的祖先时“顺便”把它的子孙直接连接到它上面。这就是路径压缩了。使用路径压缩的代码如下,时间复杂度基本可以认为是常数的。


void init(void)

{

    int i;

    for (i=0;i<MAX; i++)

        father[i] =i;

}

int get_father(int v)

{

    if (father[v]!= v)

        father[v] =get_father(father[v]);

    returnfather[v];

}

(2)rank合并

合并时将元素少的集合合并到元素多的集合中。

// 初始化

static int rank[MAX] = { 0 };

 

char judge(int x, int y)

{

    int fx, fy;

    if ((fx =get_father(x)) == (fy = get_father(y)))

        return 1;

 

    if (rank[fx]> rank[fy])

        father[fy]= fx;

    else {

        father[fx]= fy;

        if(rank[fx] == rank[fy])

           rank[fy]++;

    }

    return 0;

}

时间复杂度

O(n*α(n))

其中α(x),对于x=宇宙中原子数之和,α(x)不大于4

事实上,路经压缩后的并查集的复杂度是一个很小的常数。


原文:http://www.nocow.cn/index.php/%E5%B9%B6%E6%9F%A5%E9%9B%86

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值