并查集 C++

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/NichChen/article/details/83999055

并查集的三种实现方式:
一、快速查找QuickFind,用一个数组记录该点所属类别。
二、快速合并QuickUnion,用树的形式保存每个点所属类别,每次只连接两个根节点。
三、带路径压缩的加权快速合并(Weighted QuickUnion),记录每个树的大小(按照树中结点个数来算),将小数合入大树的根节点,并对大树中的子结点进行路径压缩,让该节点的父节点指向原父节点的父节点。

代码:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <sstream>
#include <time.h>
using namespace std;

//抽象基类
class UnionFind
{
public:
    UnionFind(int n);
    ~UnionFind();
    int Count();
    virtual bool Connected(int p, int q)=0; //纯虚函数,接口定义
    virtual void Union(int p, int q)=0;
protected:
    int *id;
    int sz;
    int num;

};

UnionFind::UnionFind(int n)
{
    this->num = this->sz = n;
    this->id = new int[n];
    for(int i = 0; i < n; ++i)
    {
        this->id[i] = i;
    }
}

UnionFind::~UnionFind()
{
    //析构函数采用delete释放内存
    delete this->id;
    delete &this->num;
    delete &this->sz;
}

UnionFind::Count()
{
    return this->num;
}


//QuickFind类(公有继承,private成员变量不可被访问,其它成员属性不变)
class QuickFind:public UnionFind
{
public:
    QuickFind(int n);
    bool Connected(int p, int q);
    void Union(int p, int q);
};

//初始化方式,与父类相同
QuickFind::QuickFind(int n):UnionFind(n) {};

bool QuickFind::Connected(int p, int q)
{
    return this->id[p] == this->id[q];
}

void QuickFind::Union(int p, int q)
{
    if(this->id[p] == this->id[q])  //无效连接
    {
        return;
    }
    int k = this->id[q];
    for(int i = 0; i < this->sz; ++i)
    {
        if(this->id[i] == k)
        {
            this->id[i] = this->id[p];
        }
    }
    this->num--;
}

//QuickUnion类
class QuickUnion:public UnionFind
{
public:
    QuickUnion(int n);
    bool Connected(int p, int q);
    void Union(int p, int q);
protected:
    int findRoot(int p);
};

//初始化方式,与父类相同
QuickUnion::QuickUnion(int n):UnionFind(n) {};

int QuickUnion::findRoot(int p)
{
    //id[i] == i,说明i结点为根节点
    while(p != this->id[p])
    {
        p = this->id[p];
    }
    return p;
}

bool QuickUnion::Connected(int p, int q)
{
    return this->findRoot(p) == this->findRoot(q);
}

//int* id 中当前结点保存的数,相当于它的父节点数
void QuickUnion::Union(int p, int q)
{
    int i = this->findRoot(p);
    int j = this->findRoot(q);
    if(i == j)  //无效连接
    {
        return;
    }
    this->id[j] = this->id[i];
    this->num--;
}

//加权QuickUnion,包括路径压缩
class WeightedQuickUnion: public QuickUnion
{
public:
    WeightedQuickUnion(int n);
    ~WeightedQuickUnion();
    void Union(int p, int q);
protected:
    int findRoot(int p);
private:
    int *sz;  //树的结点个数,而非树的深度
};

WeightedQuickUnion::WeightedQuickUnion(int n): QuickUnion(n)
{
    this->sz = new int[n];
    for(int i = 0; i < n; ++i)
    {
        this->sz[i] = 1;
    }
}

WeightedQuickUnion::~WeightedQuickUnion()
{
    delete this->sz;
}

int WeightedQuickUnion::findRoot(int p)
{
    while(p != this->id[p])
    {
        this->id[p] = this->id[this->id[p]]; //路径压缩,让该点的父节点变成当前父节点的父节点
        p = this->id[p];
    }
}

void WeightedQuickUnion::Union(int p, int q)
{
    int i = this->findRoot(p);
    int j = this->findRoot(q);
    if(i == j)   //无效连接
    {
        return;
    }
    if(this->sz[i] < this->sz[j])
    {
        this->id[i] = j;
        this->sz[j] += this->sz[i];
    } else
    {
        this->id[j] = i;
        this->sz[i] += this->sz[j];
    }
    this->num--;
}

int main()
{
    string line;
    ifstream in("mediumUF.txt");   //以读模式打开文件
//    ifstream in("tinyUF.txt");   //以读模式打开文件
    if(in)  //有文件
    {
        vector<pair<int, int>> data_pairs;
        pair<int, int> data_pair;
        bool first = true;
        int sz;
        while(getline(in, line)) {
            if(first)
            {
                sz = stoi(line);
//                cout << sz << endl;
                first = false;
            } else {
                if(line != "")
                {
                    string data1;
                    string data2;
                    stringstream input(line);
                    input >> data1;
                    input >> data2;
                    data_pair = pair<int, int>(stoi(data1), stoi(data2));
                    data_pairs.push_back(data_pair);
                }
            }
        }

        UnionFind* UF; //统一接口                Time Cost
        UF = new QuickFind(sz);              // 1~3 ms
//        UF = new QuickUnion(sz);             // 0 ms
//        UF = new WeightedQuickUnion(sz);     // 0 ms

        //耗时统计
        clock_t start, finish;
        start = clock();
        for(int i = 0; i < data_pairs.size(); ++i) {
            UF->Union(data_pairs[i].first, data_pairs[i].second);
        }
        finish = clock();
        cout << "Count = " << UF->Count() << endl;
        cout << "Connected(1, 4) = " << UF->Connected(1, 4) << endl;
        cout << "Connected(2, 5) = " << UF->Connected(2, 5) << endl;
        cout << "Time Cost = " << (double)(finish - start)/CLOCKS_PER_SEC*1000 << " ms" << endl;

//        cout << data_pairs.size() << endl;
        in.close();

    } else {
        cout << "no such file" << endl;
    }

    return 0;
}

/*********tinyUF.txt**************
10

4 3

3 8

6 5

9 4

2 1

8 9

5 0

7 2

6 1

1 0

6 7

***********************************/

猜你喜欢

转载自blog.csdn.net/NichChen/article/details/83999055
今日推荐