并查集(Disjoint Set)

目录

❤️什么是并查集?

实现方法1

实现方法2

题目1


❤️什么是并查集?

        并查集是一种数据结构,用于处理一些不交集(Disjoint sets,一系列没有重复元素的集合)的合并及查询问题。

常见的两种操作:

        -合并两个集合;                        //并

        -查找某元素属于哪个集合;      //查

实现方法1

        -用编号最小的元素标记所在的集合;

        -定义一个数组 Set[1..n] ,其中 Set[i] 表示元素 i 所在的集合

并查集(Disjoint Set)_第1张图片

不相交集合:{1 , 3 , 7} , {4} , {2, 5, 9, 10} , {6, 8} 

每个元素 i 用数组的下标表示,集合中保存的元素是集合中元素的标记。

例如:第一个不相交集合{1 , 3 , 7},这个集合的标记为最小的元素 1,则图中Set[1]、Set[3]、Set[7]都保存这个集合的标记 1。(就相当于1是集合{1 , 3 , 7}的队长,2是集合{2, 5, 9, 10}的队长)

-查找元素:时间复杂度O(1)

find_1(x){
    return Set[x];
}

例如:查找元素9是哪个集合则返回Set[9],也就是标记为2的集合。

-合并操作:时间复杂度O(N)

merge_1(a, b){
    i = min(a, b);
    j = max(a, b);
    for(int k=1; k<=N; k++){
        if(Set[k] == j)
            Set[k] = i;
    }
}

例如:合并两个集合{1 , 3 , 7} , {4},执行merge_1(1, 4),用两个集合的标记的较小值重新标记每个元素。

实现方法2

-每个集合用树来表示

对于数组Set[1..n],Set[i] = i,则 i 就是队长,也就是树根;Set[i] = j,且 j != i,则 j 就是 i 的上级,也就是父节点。

  并查集(Disjoint Set)_第2张图片

 -查找元素:最坏情况的时间复杂度O(N)

find_2(x){
    r = x;
    while(Set[r]!=r)
       r = Set[r]; 
    return r;
}

例如:查找元素10的大队长,10的上级是4,4的上级是,2的上级是他自己,那么2就是大队长。

-合并操作:时间复杂度O(1)

void merge_2(a, b){
    Set[a] = b;
}

 并查集(Disjoint Set)_第3张图片

 -避免最坏情况:上面说到,查找的最坏情况时间复杂度是O(N),如何避免最坏情况?

        方法:降低查找深度,将深度低的树合并到深度高的树。如下图所示:第一种合并结果高度为4,第二种合并结果高度为3。

并查集(Disjoint Set)_第4张图片并查集(Disjoint Set)_第5张图片

        实现:时间复杂度O(1)

merge_3(a, b){
    if(height(a)==height(b)){
        height(a) = height(a)+1;
        Set[b] = a;
    }
    else if(height(a)

         效果:最坏情况的时间复杂度变为O(logN)

题目1

Problem - 1232https://acm.hdu.edu.cn/showproblem.php?pid=1232AC代码:

#include
using namespace std;

int city[1001];
int findBoss(int a){
    int boss = a;
    while(city[boss]!=boss){
        boss = city[boss];
    }
    return boss;
}
void changeBoss(int a, int b){
    int aBoss = findBoss(a);
    int bBoss = findBoss(b);
    if(aBoss != bBoss){
        city[aBoss] = bBoss;
    }
}

int main (){
    int N, M, x, y, number;

    while(cin >> N, N){
        number = -1;
        for(int i=1; i<=N; i++)
            city[i] = i;
        cin >> M;
        for(int i=0; i> x >> y;
            changeBoss(x, y);
        }
        for(int i=1; i<=N; i++)
            if(city[i]==i) number++;
        cout << number << endl;
    }

    return 0;
}

你可能感兴趣的:(算法,数据结构,c++)