并查集路径压缩(C++)

一、并查集:查找元素互相关联的集合

Keep Learning 34days;
合并:合并两个集合
查找:判断两个元素是否在一个集合

1、利用数组 father[]

int father[N];			//表示元素i的最高父亲节点(根节点)

如果father[i] = i,说明i是其集合的 根节点(最高点)

2、开始每一个元素都是自己单独一个集合,令father[i] = i;

for(int i = 0;i <= n;i++)
	father[i] = i;

3、查找:由于每个集合只能有一个根节点,所以访问每个元素的根节点要不断寻找,直到father[i] = i;

int findFather(int x)
{
    
    
	while (x != findFather(x))		//只要当前节点还不是根节点
	{
    
    
		x = father[x];		//元素等于自身父亲节点
	}
}

4、 判断两个元素是否在一个集合,只要判断他们两个的根节点是否相同:

bool judge(int a, int b)
{
    
    
	if (father[a] == father[b])		//如果根节点一样
		return true;
	else
		return false;

5、合并两个元素到一个集合中的操作,比如让元素a和元素b合并到一个集合中,只需将father[ findFather[a] ] = findFather(b)或者反过来也可以:

if(findFather(a) != findFather(b))				//如果两个元素不在一个集合中,合并集合
	father[ findFather[a] ] = findFather(b)//更新a的根节点的父亲节点为b的根节点

二、路径压缩:以上并查集没有进行过优化,效率运行低、慢,当你回溯去寻找父亲节点时时间复杂度为O(n),如果有10五次幂显然无法承受

1、举个栗子:fa[1]=1,fa[2]=1,fa[3]=2,fa[4]=3;

这样完全可以等价的变为:fa[1]=1,fa[2]=1,fa[3]=1,fa[4]=1;
在这里插入图片描述
相当于把同一集合所有查询路径上的父亲节点都指向根节点,时间复杂度降到了O(1)

int findFather2(int x)
{
    
    
	int a = x;				//由于最后x要变成它的根节点的值,所以先备份它
	while (x != findFather(x))		
	{
    
    
		x = father[x];		
	}
	while (a != father[a])		//再用x初始值循环一遍
	{
    
    
		int z = a;			//由于a查找的过程又会被覆盖,每次用z来备份
		a = father[a];		//先将当前节点变为其父亲节点
		father[z] = x;		//再将刚刚的节点的父亲节点改为根节点的值
	}
}

后语:终于知道前几天做的题为什么只能得54分了,34days

猜你喜欢

转载自blog.csdn.net/Kyrie_irving_kun/article/details/114849966