并查集

Posted eimadrigal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集相关的知识,希望对你有一定的参考价值。

一、概念

一个集合中的元素,仅有的关系就是同属于这个集合,并查集就是用来维护若干集合的一种数据结构。
并查集有两个基本操作:

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

为了方便地实现合并以及查找操作,我们在一个集合中规定唯一一个根结点,并将这个根结点作为该集合的标志。
开始时所有元素都是一个独立的集合:

int parent[MAXN];
for(int i = 0;i < n;i++)
{
    parent[i] = i;    //i元素的父结点初始化为自己,也可以初始化为-1
}

二、合并与查找

  • Find
    查找的同时可以通过路径压缩来将均摊复杂度降低为(O(1))。查找某个结点时,将其经过的全部直接连到父结点,这样下次查询时次数就会减少。
  • Union
    合并时可以遵循按秩合并原则,将秩小的树合并到秩大的树,降低路径压缩时的开销。
    将两个不同的集合合并为一个集合,只要将其中一个集合的根结点的parent指向另一个集合的根结点即可。
    对于属于同一个集合的两个元素的合并没有意义,所以我们一般只对两个不同的集合进行合并。
class unionFind {
private:
    vector<int> parents_;
    vector<int> ranks_;
public:
    unionFind(int n) {
        ranks_ = vector<int>(n, 0);
        parents_ = vector<int>(n, 0);
        for(int i = 0;i < parents_.size();i++) {
            parents_[i] = i;
        }
    }

    // get the root of x
    int Find(int x) {
        // path compression
        if(x != parents_[x]) {
            parents_[x] = Find(parents_[x]);
        }
        return parents_[x];
    }

    // merge set u and v
    // false -> u and v are already in one set
    bool Union(int u, int v) {
        int rootu = Find(u);
        int rootv = Find(v);
        if(rootu == rootv) 
            return false;

        // merge low rank to high rank
        if(ranks_[u] < ranks_[v]) {
            parents_[u] = v;
        }
        else if(ranks_[v] < ranks_[u]) {
            parents_[v] = u;
        }
        else {
            parents_[u] = v;
            ranks_[v]++;
        }

        return true;
    }
};

以上是关于并查集的主要内容,如果未能解决你的问题,请参考以下文章

想要学会并查集吗?看我四十行代码实现它

树--12---并查集

笔记并查集---无向图处理代码模板及类型题

并查集

力扣 每日一题 886. 可能的二分法难度:中等,rating: 1794(并查集 / 拆点优化的扩展域并查集)

并查集