//实现并查集的数据结构定义,并实现 Union、Find 两个基本操作
#define SIZE 13
int UFSets[SIZE]; //用一个数组表示并查集
//初始化并查集
void Initial(int S[]) { //S即为并查集
for (int i = 0; i < SIZE; i++) //每个自成单元素集合
S[i] = -1;
}
//Find “查”操作,找x所属集合(返回x所属根结点)
/*判断两个元素是否属于同一集合,只需分别找到他们的根,比较是否相同即可*/
int Find(int S[], int x) {
while (S[x] >= 0) //循环寻找x的根
x = S[x];
return x; //根的S[]小于0
}
//Union “并”操作,将两个集合合并为一个
/*求两个不相交子集合的并集,需先找到两个元素的根,再令一棵子集树的根指向另一棵子集树的根*/
void Union(int S[], int Root1, int Root2) {
if (Root1 == Root2) return; //要求Root1与Root2是不同的集合
S[Root2] = Root1; //将根Root2连接到另一根Root1下面
}
//可采取“小树合并到大树”的策略优化 Union操作
//Union “并”操作,小树合并到大树
/*极端情况下,n个元素构成的集合树深度为n,则find最坏时间复杂度为O(n)
改进方法:在Union前,先判别子集中的成员数量,然后令成员少的根指向多的根(小树合并到大树)
此外,根节点的绝对值保存集合树中成员数量,此方法深度不超过1+logn*/
void Union(int S[], int Root1, int Root2) {
if (Root1 == Root2) return;
if (S[Root2] > S[Root1]) { //Root2结点数更少
S[Root1] += S[Root2]; //累加结点总数
S[Root2] = Root1; //小树合并到大树
}
else {
S[Root2] += S[Root1]; //累加结点总数
S[Root1] = Root2; //小树合并到大树
}
}
//可采取“路径压缩”的策略优化 Find 操作
//Find “查”操作优化,先找到根节点,再进行“压缩路径”
/*随着子集的合并,集合树深度越来越大,为减少查找时间,现对Find优化
优化方案:当所查元素x不在树的第二层时,在算法中增加一个“压缩路径”的功能
此功能可将根到元素x路径上的所有元素都变成根的孩子*/
int Find(int S[], int x) {
int root = x;
while (S[root] >= 0) root = S[root]; //循环找到根
while (x != root) { //压缩路径
int t = S[x]; //t指向x的父节点
S[x] = root; //x直接挂到根节点下
x = t; //循环
}
return root; //返回根节点编号
}