不相交集ADT
ADT的知识很简单, 类似于游标, 但还有它的专业解释
等价关系
等价关系是满足下列三个性质的关系R:
(自反性)对于所有的a∈S,aRa
(对称性)aRb当且仅当bRa
(传递性)若aRb且bRc,则aRc.
动态等价性问题
一个元素a∈S的等价类是S的一个子集,它包含所有a有关系的元素。有两种运算允许进行。第一种是Find,返回包含给定元素的集合(即等价类)的名字。第二种运算时添加关系。使用求并运算Union,把含有a和b的两个等价类合并成一个新的等价类。
不过, 只是说说也不及看图和看代码理解的快, 深刻
代码也是很简单明了
//初始化, 全部角标初始化为 -1
void Re_Creat(Arr a)
{
int i = N;
for (; i > 0; i--)
a[i] = -1;
}
并集
//将其角标改为对应的数组的角标, 即指向该数组
void Un(Arr a, Elenment un, Elenment un_1)
{
a[un] = un_1;
}
路径压缩
a[i]等于由Find返回的值, 这样, 在集合的根被递归地找到以后, i 就直接指向它, 就不会在递归的一个一个的返回了, 实现了路径的压缩
int Find(Arr a, Elenment find)
{
if (a[find] <= 0)
return find;
else
return a[find] = Find(a, a[find]);
}
ADT的应用
一个例子是计算机网络和双向连接表,每一个连接将文件从一个计算机传递到另一个计算机。现在的问题是能否将文件从任意一个计算机传递到另一个任意的计算机,并且这个问题要on-line解决。
解决这个问题,就可以用到上面的数据结构。开始阶段我们可以把每一台计算机放到他自己的集合中,要求两台计算机传递文件当且仅当这两台计算机在同一个集合中。因此传输文件能力相当于一个等价关系。当我们需要传输文件时,检验两个计算机是否在同一个集合里,是的话就传输文件,否的话,就用Union方法把它们合并到一个集合中,然后传输文件。
源代码
#include <stdlib.h>
#include <stdio.h>
const int N = 100;
typedef int Arr[N + 1];
typedef int Elenment;
//初始化一般为 -1, 0;
void Creat(Arr a)
{
int i = N;
for (; i > 0; i--)
a[i] = 0;
}
void Re_Creat(Arr a)
{
int i = N;
for (; i > 0; i--)
a[i] = -1;
}
//两种并集的方法, Re_Un 是按高度求并, 保证树枝深度
void Un(Arr a, Elenment un, Elenment un_1)
{
a[un] = un_1;
}
void Re_Un(Arr a, Elenment un, Elenment un_1)
{
if (a[un] < a[un_1])
a[un_1] = un;
else
{
if (a[un] == a[un_1])
a[un_1]--;
a[un] = un_1;
}
}
int Find(Arr a, Elenment find)
{
if (a[find] <= 0)
return find;
else
return a[find] = Find(a, a[find]);
}
int main()
{
Arr a;
Re_Creat(a);
for (int i = 1; i < 11; i++)
printf("%d = %d\n", i, a[i]);
Re_Un(a, 1, 3);
Re_Un(a, 5, 3);
Re_Un(a, 7, 4);
Re_Un(a, 8, 2);
Re_Un(a, 9, 5);
Re_Un(a, 3, 2);
Re_Un(a, 2, 4);
for (int i = 1; i < 11; i++)
printf("%d = %d\n", i, a[i]);
if (Find(a, 1) != Find(a, 7))
Re_Un(a, 9, 10);
for (int i = 1; i < 11; i++)
printf("%d = %d\n", i, a[i]);
system("pause");
return 0;
}