(16)数据结构-并查集

1、定义

并查集:“并”Union, “查”Find 集合。并查集是一种维护集合数据结构。支持一下两个操作。
(1)合并:合并两个集合
(2)查找:查找两个元素是否在同一个集合

2、数据结构

实际上就只用一个数组就行了。farther[MaxSize]。
p[x] = y; 代表的是x的父亲是y。

3、函数实现

void Init(int n);
int FindFarther(int x);
void Union(int a, int b);

3.1 初始化

void Init(int n){
    
    
    for(int i = 1; i <= n; i++){
    
    
        farther[i] = i;
        IsRoot[i] = false;
    }
}

3.2 合并

void Union(int a, int b){
    
    
    int Fa = FindFarther(a);
    int Fb = FindFarther(b);
    if(Fa != Fb){
    
    
        farther[Fb] = Fa;
    }
}

3.3 查找父节点

int FindFarther(int x){
    
    
    int a = x;
    while(x != farther[x]){
    
    
        x = farther[x];
    }
    //压缩路径
    while(a != farther[a]){
    
    
        int z = a;
        farther[a] = x;
        a = farther[z];
    }
}
输入:
7 5
1 2 
2 3
3 1
1 4
5 6

输出:
cal: 4
cal: 2
cal: 1
3

4、完整代码

#include<iostream>

#define MaxSize 110
using namespace std;

int farther[MaxSize];
bool IsRoot[MaxSize] ={
    
    false};

//计算每个集合中有多少个节点
int cal[MaxSize] = {
    
    0};

void Init(int n);
int FindFarther(int x);
void Union(int a, int b);

int main(){
    
    

    int n,m;
    cin >> n >> m;
    Init(n);

    while(m--){
    
    
        int a , b;
        cin >> a >> b;
        Union(a,b);
    }

    for(int i = 1; i <= n; i++){
    
    
        IsRoot[FindFarther(i)] = true;
        cal[FindFarther(i)]++;
    }

    for(int i = 1; i<=n; i++){
    
    
        if(cal[i] !=0){
    
    
            cout << "cal: " << cal[i] << endl;
        }
    }

    int count = 0;
    for(int i = 1;i <= n; i++){
    
    
        count += IsRoot[i];
    }
    cout << count << endl;

    return 0;
}

void Init(int n){
    
    
    for(int i = 1; i <= n; i++){
    
    
        farther[i] = i;
        IsRoot[i] = false;
    }
}

void Union(int a, int b){
    
    
    int Fa = FindFarther(a);
    int Fb = FindFarther(b);
    if(Fa != Fb){
    
    
        farther[Fb] = Fa;
    }
}

int FindFarther(int x){
    
    
    int a = x;
    while(x != farther[x]){
    
    
        x = farther[x];
    }
    //压缩路径
    while(a != farther[a]){
    
    
        int z = a;
        farther[a] = x;
        a = farther[z];
    }
}

5、小结

并查集的实现和静态链表的实现类似,数组的下标代表着当前的节点。初始化为了让每个节点的父节点为本身。一整套Union完成以后,所有的数据都被分成几个类别了(因为每个节点的父节点都已经确定了)。在Findfarther函数中,“压缩路径”的目的是让每个节点的上一个节点直接是父节点。这种存储方式是的每次查找节点父节点的时候的时间复杂度为O(1)。如果不进行这一步的优化,每次查找父节点的时间复杂度为O(n)。

Guess you like

Origin blog.csdn.net/xdg15294969271/article/details/120516482