并查集的三种实现方式:
一、快速查找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
***********************************/