并查集

最近做题学习了一点之前学并查集所没有学到的东西。下面整理如下:

1.如何在并的时候统计每个集合大小?

之前在啊哈算法里面看到的father[ ]数组初始化是这样的:

int i;
for(i = 1;i <= n; i++) father[i] = i;//一开始,每个元素独立成为一个集合,每个元素的父亲节点都是自己。

但是这样有一个问题:就是无法计算每个集合元素的个数。

如果这样初始化:

int i;
for(i = 1;i <= n; i++) father[i] = -1;//可以理解为都没有父节点,那么用-1表示没有。

那么“-1”除了理解为没有之外,还可以理解为:这个集合有|-1|=1个元素。
那么只要每次在并的时候,将父亲节点的father[ ]加上被并的集合大小,就可以记录下来这个集合当前元素的个数。同时这个负数依然可以理解为没有父节点,即其本身为父节点。

2.尽量减小时间复杂度。

在合并的时候,可以把节点少的树并到节点多的树里面,这样整个树的高度会尽可能的保持不变,以此来提升并查集的运行速度。
代码如下:

void merge(int a, int b)
{
  int r1 = find(a);
  int r2 = find(b);//先找到两棵树的根节点。
  
  if(father[r1] < father[r2])//r1是大树根节点
  {
  	father[r1] += father[r2];
  	father[r2] = r1;
  }
  else //r2是大树根节点
  {
  	father[r2] += father[r1];
  	father[r1] = r2;
  }
  
}

3.并查集中“查”的算法。

  1. 非路径压缩。
int find(int x)//father[i] = i;
{
	while(x != father[x]) x = father[x];
	return x;
}

int find(int x)//father[i] = -1
{
	while(father[x] >= 0) x = father[x];
	return x;
}
  1. 路径压缩。(递归)
int find(int x)//father[i] = i
{
	if(father[x] != x) father[x] = find(father[x]);
	return father[x];
}
/* 对于father[i]=-1的情况不能这么写 */
  1. 路径压缩。(非递归)
int find(int x)
{
	int root = x;
	while(root != father[root]) root = father[root];//首先找到根节点
	/* 或者while(father[root] >= 0)  root = father[root]; */

	int temp;
	while(x != root)
	{
		temp = father[x];
		father[x] = root;
		x = temp;
	}//将从x到根节点沿路的所有节点全部直接指向根节点
	return root;
}

以后有学到的东西再添吧~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值