算法——并查集

并查集是一种树状数据结构,用来处理不相交的集合的关系,它的查找速度非常快,在并查集中只存在两种关系,要么是属于关系,要么是不想交的补集关系。

并查集有四种基本操作,初始化,查询,合并以及判断是否属于同一集合,可以用数组实现,也可以用指针实现,北理ACM祖传的是数组实现的方法。用数组来完成指向父节点的操作。所以我们首先需要一个数组fa[]来存放各个元素的父亲节点。

void init(int size)
{
	for (int i = 0; i < maxn; i++)
	{
		fa[i] = i;
		deep[i] = 0;
	}
}

除了父子关系我们还要考虑整个树的深度,方便以后的优化来节省查询的时间,所以还有一个deep数组来存放该结点树的深度。

可以看到,在初始时每一个节点自身是一个独立的集合,本身就是该集合的关键字元素(我们用一个关键字元素,也可以说是根节点,也就是该集合的其他节点的父亲元素都是这个节点),我们希望用更短的时间去找到某一个元素,所以最期望的情况是我们从某个节点只访问一次就查询到根节点,也就是说所有的元素都直接连在根节点上。这个事情需要维护,我们在查询的时候,如果发现某个元素经过了中间元素才访问到根节点,那么我们需要这个节点i的fa[i]值成为根节点的下标,而在查询时由于是递归的过程,我们直接赋值,就省去了还要函数栈一步步返回在赋值的繁琐。

int find(int x)
{
	if (fa[x] == x)
		return x;
	return fa[x] = find(fa[x]);
}

合并两个并查集时,考虑两棵树的树高不同,如果将高的树接在矮的树的根节点上,那么访问新的树的最坏程度要高的树的高+1(矮树的根节点),而将矮的树合并到高的树上并不会影响树的深度(最远的子节点到根节点的距离),显然我们选择后者会更加的合理。但是要注意的是当两个树的深度相等时,一定要将合并后根结点的deep值+1,因为无论怎样合并树高都会增加。

void unite(int x, int y)
{
	x = find(x);
	y = find(y);
	if (x == y)
		return;
	if (deep[x] < deep[y])
		fa[x] = y;
	else
	{
		fa[y] = x;
		if (deep[x] = deep[y])
			deep[x]++;
	}
}
最后检测是否在同一个集合则非常简单了,直接find根节点比较下标是否相等就可以了。

bool same(int x, int y)
{
	return find(x) == find(y);
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值