等价类可以采用树结构表示。用一棵树代表一个集合,如果两个结点在同一棵树中,则认为这两个结点在同一个集合中。
用树结构表示的等价类,大多数情况下,其存储方法采用双亲表示法。具体的存储结构可以采用元素集合存储在一个数组中,所有相同的等价类放在同一个根结点的树中,树用双亲表示法表示。
例1 设集合X={x|1≤x≤10,且x是整数},R是X上的等价关系。
R = {(1,3),(3,5),(3,7),(2,4),(4,6),(2,8)}
求出集合X的关于R的等价类,并画出存储结构示意图2。
说明:这里省略了类如(1,1)的自反关系、类如(3,1)的对称关系以及类如(1,5)的部分传递关系。
根据前面讨论的并查算法,设计一个程序,完成例1的等价类建立。
typedef struct
{
int data; //数据元素
int parent; //双亲结点
}ESet;
void Initialize(ESet x[], int n)//初始化
{
for(int e = 1; e <= n; e++)
{ x[e].data = e;
x[e].parent = -1;
}
}
int Find(ESet x[], int i) //查
{ int e = i;
while(x[e].parent >= 0) //找到根
e = x[e].parent;
return e;
}
void Union(ESet x[], int i, int j) //并
{
x[j].parent = i; //将j并入i
int e = Find(x, i);
x[e].parent = x[e].parent - 1; //累加
}
void main(void)
{ int n =10;
ESet *x = new ESet[n+1];
Initialize(x, n);
if( Find(x, 1) != Find(x, 3)) Union(x, 1, 3);
if( Find(x, 3) != Find(x, 5)) Union(x, 3, 5);
if( Find(x, 3) != Find(x, 7)) Union(x, 3, 7);
if( Find(x, 2) != Find(x, 4)) Union(x, 2, 4);
if( Find(x, 4) != Find(x, 6)) Union(x, 4, 6);
if( Find(x, 2) != Find(x, 8)) Union(x, 2, 8);
for(int e = 1; e <= n; e++)
cout << x[e].data << " " << x[e].parent << endl;
}
程序运行的输出结果如下:
1 -4
2 -4
3 1
4 2
5 3
6 4
7 3
8 2
9 -1
10 -1
程序运行的输出结果和图2所示的等价类树完全相同。