一、实现程序:
#include <iostream>
using namespace std;
struct Node { // 并查集结点类
int data; // 保存数据
int parent; // 保存父结点
};
class UnionFindSets {
public:
UnionFindSets(int w[], int n); // 构造函数
~UnionFindSets(); // 析构函数
void Union(int a, int b); // 并
bool Find(int a, int b); // 查找两个数是否在同一集合
private:
Node *s; // 数组
int currentSize; // 实际存储的个数
int Find(int x); // 查找x,并返回x的根结点
int CollapsingFind(int i); // 路径压缩
};
// 构造函数
UnionFindSets::UnionFindSets(int w[], int n) {
// 初始化
currentSize = n;
s = new Node[n];
for(int i = 0; i < n; i++) {
s[i].data = w[i];
s[i].parent = -1;
}
}
// 析构函数
UnionFindSets::~UnionFindSets() {
delete []s; // 释放空间
}
// 并:根结点保存(-结点数),是结点的相反数,一个负数
void UnionFindSets::Union(int a, int b) {
int root1, root2;
root1 = Find(a); // 找到a的根结点
root2 = Find(b); // 找到b的根结点
if(root1 == root2 || root1 == -1 || root2 == -1) // 根结点相同,或者其中一个数不在集合中
return;
// 根结点不同,才将两棵树合并
if(s[root1].parent <= s[root2].parent) { // 说明root1的结点数比root2的结点数大或相同
s[root2].parent = root1; // 将root2树合并到root1树中
s[root1].parent = s[root1].parent + s[root2].parent; // 保存结点数
}
else { // root1的结点数比root2的结点数少
s[root1].parent = root2;
s[root2].parent = s[root1].parent + s[root2].parent; // 保存结点数
}
}
// 查找两个数是否在同一集合
bool UnionFindSets::Find(int a, int b) {
int root1, root2;
root1 = Find(a); // 查找a的根结点
root2 = Find(b);
if(root1 != root2) // 根结点不同,说明不在同一集合
return false;
return true; // 在同一集合,返回true
}
// 查找x,并返回x的根结点
int UnionFindSets::Find(int x) {
int i;
for(i = 0; i < currentSize && s[i].data != x; i++); // 在数组中查找
if(i >= currentSize) // 没找到
return -1;
i = CollapsingFind(x); // 找根结点,并进行路径压缩
return i;
}
// 路径压缩:对结点i这条路径上的结点,将根结点变为各个结点的父结点
int UnionFindSets::CollapsingFind(int i) {
int j, temp;
for(j = i; s[j].parent >= 0; j = s[j].parent); // 往上找根结点
while(i != j) { // 当父结点不为根
temp = s[i].parent; // 保存i的当前父结点
s[i].parent = j; // 把根结点变为i的父结点
i = temp; // 对i的原父结点也做路径压缩,直到父结点为根结点为止
}
return j;
}
int main(int argc, const char * argv[]) {
int w[] = {3, 8, 10, 1, 5, 4}, choice, a, b;
int len = sizeof(w)/sizeof(w[0]); // 数组的长度
bool finished = false;
UnionFindSets uf(w, len); // 创建并查集对象
while(!finished) {
cout << "[1]并" << endl;
cout << "[2]查" << endl;
cout << "[3]退出" << endl;
cout << "请输入你的选择[1-3]:";
cin >> choice;
switch(choice) {
case 1:
cout << "请输入两个要进行并运算的元素:" << endl;
cin >> a >> b;
uf.Union(a, b); // 并
break;
case 2:
cout << "请输入两个要检查是否在同一集合的元素:" << endl;
cin >> a >> b;
if(uf.Find(a, b)) // 是
cout << "Yes" << endl;
else // 否
cout << "No" << endl;
break;
case 3:
finished = true;
break;
default:
cout << "输入错误,请重新输入!" << endl;
}
}
return 0;
}
测试: