若对于每一对元素(a,b),a、b属于S,aRb或者为true或者为false,则称在集合S上定义关系R。如果aRb是true,那么我们说a与b有关系。
等价关系是满足下列三个性质的关系R:
- 自反性:对于所有的a属于S,aRa;
- 对称性:aRb当且仅当bRa;
- 传递性:若aRb且bRc,则aRc; ’
所以,不相交集实质上就是各个等价类组成的集合。
不相交集允许的运算:Find和Union。
Find:返回包含给定元素的集合(即等价类)的名字;
Union:添加关系aRb,若a、b不在同一个等价类中,则使用Union把a、b合成一个等价类。
不相交集的类型声明:
#include<stdio.h>
#define NumSets 1000
typedef int DisjSet[NumSets+1];
typedef int SetType;
typedef int ElementType;
void Initialize(DisjSet s)
{
int i;
for (i = NumSets; i > 0; i++)
s[i] = 0;
}
不相交集运算的实现:
void SetUnion(DisjSet s, SetType root1, SetType root2)
{
s[root2] = root1;
}
SetType Find(ElementType x, DisjSet s)
{
if (s[x] <= 0)
return x;
else
return Find(s[x], s);
}
下面是对算法的改进:
灵活求并的算法:
分为按高度和按大小求并。
- 按大小求并:总让较小的树成为较大的树的子树,每个根的数组元素包含其树大小的负值;
- 按高度(秩)求并:浅的树成为深的树的子树。只有两棵树相等深度求并时,树的高度才增加。每个根的数组元素包含其树高度的负值。
void SetUnion(DisjSet s, SetType root1, SetType root2)
{
if (s[root2] < s[root1])
s[root1] = root2;
else
{
if (s[root1] == s[root2])
s[root1]--;
s[root2] = root1;
}
}
基于路径压缩的Find算法:
路径压缩只在Find操作执行期间执行,与Union操作无关。路径压缩的效果为:从结点x到根的路径上的每一个结点,都使它的父节点变为根。由此对这些结点未来的快速访问将由于花费额外的工作来进行路径压缩而得到补偿。
SetType Find(ElementType x, DisjSet s)
{
if (s[x] <= 0)
return x;
else
return s[x]=Find(s[x], s);
}