• 何为并查集


    1.并查集的基本概念

    并查集是用于集合合并和元素查询的一种数据结构。主要有两个功能,一是合并元素到同一个集合中;二是查询一个元素属于哪一个集合。

    因此,可以设计一个接口用来规定并查集的特性,具体的实现可以根据具体应用灵活处理。接口中元素x,y分别是只得元素的编号,而并不一定是真实的元素,真实的元素可以根据具体的应用进行确定。

         

    class IDisjointset{

    public:

    virtual void init_set() = 0;

    virtual void union_set(int x, int y) = 0;

    virtual int find_set(int x) = 0;

    };

       

    2.采用map实现的并查集

    如果使用一个map来实现并查集,实现接口,class CMdjs : public IDisjointset,函数的override申明就不再给出了,仅仅给出成员变量和构造函数。 显然,这种实现方式中,同一个集合中的元素应该有相同的groupid值。

    class CMdjs:public IDisjointset{

        public:

        CMdjs(int n){

            this.n=n;

        }

        private:

        int n;

        map<int,int>groupid;

    };

    一开始使用并查集时,需要将所有元素都看作独立的集合,即,为每个元素都分配一个group id.因此可以这样实现并查集的初始化:

    void CMdjs::init_set(){

        //n为元素的个数

        for(int i=0;i<n;i++)groupid[i]=i;

    }

    对于合并操作,给定需要合并的元素xy,不能简单的将xygroupid设为相同的值,因为如果 x属于集合Ay属于集合B,那么需要把B中所有的元素的groupid改成A的,而不是只改元素y的。

    void CMdjs::union_set(int x,int y){

        //将元素y对应的集合中的元素的groupid全部改为x

        const int gid=groupid[y];

        for(int i=0;i<n;i++){

            if(groupid[i]==gid) groupid[i]=groupid[x];

        }

    }

    对于查询操作,给定元素,应该返回其属于哪一个集合,即需要给出groupid.

    void CMdjs::find_set(int x){

        return groupid[x];

    }

       

    3.实现的时间复杂度分析

    对于初始化操作,显然需要O(n)的复杂度;

    对于合并操作,如果考虑map的查询时间,需要O(nlogn)的复杂度;

    对于查找操作,如果考虑map的查询时间,则需要O(logn)的复杂度。

     

    4.两种实现并查集的思路

    通过判断给出集合的方式,可以将并查集的实现方式分为两种,一种是采用串联式,一种是采用平行式。假设有123456一共6个节点,这6个节点是需要合并成一个集合的,现在假设123已经合并,456已经合并,现在得知25属于同一个集合,进行合并操作,可能有两种肯能的实现方式.

    4.1 串联式实现方式

    如下表。

    节点

    1

    2

    3

    4

    5

    6

    指向

    2

    3

    3

    5

    6

    6

    这里实际上是一个路径表,表示1指向22指向3,这样就知道123是属于同一个集合的,这里指向的最终的节点就可以作为集合号,例如这里的36. 现在要将25划分到同一个集合,那么需要将2所在的集合和5所在的集合合并,而不是简单的把2指向5.因此需要先找到25属于哪个集合,查询得知属于集合3和集合6,那么将节点3指向节点6即可。

    节点

    1

    2

    3

    4

    5

    6

    指向

    2

    3

    6

    5

    6

    6

    4.2平行式实现方式

    如下表。

    节点

    1

    2

    3

    4

    5

    6

    集合号

    1

    1

    1

    4

    4

    4

    平行事实现每次直接将所有的待合并的集合中的元素的集合号设定为另一个集合的集合号,这里如果要合并25所代表的集合,那么只需要查询得到25分别属于集合1和集合4,可以将集合4中的所有元素的集合号全部设定为1即可。

    节点

    1

    2

    3

    4

    5

    6

    集合号

    1

    1

    1

    1

    1

    1

    显示上面采用的实现方式是第二种。

    4.3两种实现方式比较

    如果不考虑底层数据结构的查询时间(例如采用红黑树实现的map的查询时间是O(logn)),比较两种方式的时间复杂度比较如下表(空间复杂度相同):

     

    串联式

    平行式

    查询

    O(n)

    O(1)

    合并

    O(n)

    O(k)最差O(n)

  • 相关阅读:
    问题 L: Robots
    最强阵容
    [学习][Math]康托展开和逆康托展开
    [学习][STL]next_permutation
    [动态规划][数位dp]F(x)
    [动态规划][数位dp]Bomb
    [动态规划][数位dp]不要62
    [动态规划][树形dp]Bichrome Tree
    [思维]Finite Encyclopedia of Integer Sequences
    [二分答案]gpa
  • 原文地址:https://www.cnblogs.com/vector1234/p/13552856.html
Copyright © 2020-2023  润新知