数据结构:并查集

1 介绍

在集合处理中,在初始状态,每个元素构成一个单元素的集合,然后按照一定的顺序将属于同一组的元素合并在同一个集合中,需要反复查找一个元素在哪个集合中,这类问题看似不复杂,但数据量极大,使用正常的数据结构来描述,在空间上过大,计算机无法承受,即使空间通过,时间复杂度也极高,在算法设计中很难在短时间内通过。

因此,就需要用并查集,是一种树形的数据结构。

主要用于解决一些元素分组的问题,管理一系列不相交的集合。

并查集主要有三个操作:

初始化

把每个点所在的集合,初始化为其自身组成的一个单元素的集合。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,时间复杂度O(n)。

查找

查找元素所在的集合,即根节点

合并

将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。

2 实现

class UnionFind {
    private:
    unordered_map<int,int> father;
    public:
    void init(vector<int> nums) {
        for(int i = 0; i<nums.size(); i++) {
            father.emplace(nums[i],nums[i]);
        }
    }

    int find(int x) {
        if(father.count(x) == 0) return NULL;
        if(father[x] == x) return x; //不需要做后续处理,自己就是根 

        int root = x;
        while(root != father[root]) root = father[root];

        while(x != father[x]) {
            int cur = x;
            x = father[x];
            //				father.emplace(cur,root);  //emplace 插入时,key存在则不变,就是这个地方导致超时 
            father[cur] = root; 
        }
        return root;
    }

    void merge_union(int x, int y) {
        //y合并到x内,即x的根节点作为合并后的总根 
        x = find(x);
        y = find(y);
        if(x == y) return;
        if(x==INT_MAX || y==INT_MAX) return;

        father[y] = x;
    }

    void print_ufset() {
        for(unordered_map<int,int>::iterator it=father.begin(); it!=father.end(); it++)
            cout<<"num: "<<it->first<<" father: "<< it->second<<endl;
    }
};

3 使用技巧(适用哪些算法)

后续补充......

posted @ 2021-05-25 14:03  KyrieLiu  阅读(148)  评论(0编辑  收藏  举报