不相交集

       不相交集是一种解决等价问题的数据结构。什么是等价关系呢,若对于每一对元素(a,b),a,b属于S,aRb或者为true或者为false,则称在集合S上定义关系R。如果aRb是true,那么a与b有关系。
等价关系是满足下列三个性质的关系R:
    1.自反性。对于所有的a属于S,aRa。
    2.对称性。aRb当且仅当bRa。
    3.传递性。若aRb且bRc则aRc。


基本数据结构
不相交集ADT有两种运算:
第一种运算是Find,它返回包含给定元素的集合(即等价类)的名字。
第二种运算是Union,通过对a和b执行Find并检验它们是否在同一个等价类中,若它们不在同一等价类中,那么通过使用求并运算Union把含有a和b的两个等价类合并成一个新的等价类。


       可以用树来表示每一个集合,集合的名字由根处的节点给出。由于只需要父节点的名字,因此我们可以假设树被非显式地存储在一个数组中:数组的每个成员P[i]表示元素i的父亲。如果i是根,那么P[i]=0。
    1.Find操作返回任何特定的名字,而只是要求当且仅当两个元素属于相同的集合时,作用在这两个元素上的Find返回相同的名字。即:Find(a)=Find(b)当且仅当a和b在同一个集合中。
    2.Union执行即使一个节点的根指针指向另一棵树的根节点。这种操作花费常数时间。

typedef int DisjSet[Numsets + 1];
typedef int SetType;
typedef int ElementType;

void Initialialize(DisjSet S);
void SetUnion(DisjSet S,SetType root1,SetType root2);
SetType Find(ElementType x,DisjSet S);

void Initialialize(DisjSet S)
{
	int i;
	for (i = Numsets; i > 0; i--)
		S[i] = 0;
}

void SetUnion(DisjSet S, SetType root1, SetType root2)  //Union操作 
{
	S[root2] = root1;
}

SetType Find(ElementType x, DisjSet S)  //递归实现Find
{
	if (S[x] <= 0)
		return x;
	else
		return Find(S[x],S);
}

SetType Find2(ElementType x, DisjSet S)  //迭代实现Find
{
	ElementType r = x;
	while (S[r] > 0)
		r = S[r];
	return r;
}

灵巧求并算法
1.按大小求并:总让较小的树成为较大的树的子树。
       如果Union都是按照大小进行的那么任何节点的深度均不会超过logN。因此Find操作的运行时间是O(logN),而连续M次操作则花费O(MlogN)。
       为了实现这种方法,我们需要记住每一棵树的大小。由于我们实际上只使用一个数组,因此可以让每个根的数组元素包含它的树的大小的负值。

void SetUnion(DisjSet S, SetType root1, SetType root2)
{
	if (S[root2] < S[root1]) {   //root2 较大
		S[root2] += S[root1];
		S[root1] = root2;
	}
	else {
		S[root1] += S[root2];
		S[root2] = root1;
	}
}
2.按高度求并:总让较浅的树成为深的树的子树。
void SetUnion(DisjSet S, SetType root1, SetType root2)
{
	if (S[root2] < S[root1])   //root2 较深
		S[root1] = root2;
	else {
		if (S[root1] == S[root2])
			S[root1]--;
		S[root2] = root1;
	}
}
路径压缩
       路径压缩在一次Find操作期间执行而与用来执行Union的方法无关。设操作为Find(X),此时路径压缩的效果是,从X到根路径上的每一个节点都使它的父节点变成根。
       唯一的变化是使得S[X]等于由Find返回的值。这样,在集合的根被递归地找到以后,X就直接指向它。对通向根的路径上的每个节点这将递归地出现,因此实现了路径压缩。

SetType Find(ElementType x, DisjSet S)
{
	if (S[x] <= 0)
		return x;
	else
		return S[x] = Find(S[x],S);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值