并查集详解

   日期:2021-03-25     浏览:96    评论:0    
核心提示:数据结构-并查集并查集是维护集合的数据结构 它支持合并(Union) 查找(Find)功能首先需要一个father数组(int father[N])存放父亲结点father[i]表示元素i 的结点的父亲结点例如 father[1] = 2;表示结点1的父亲结点是2;在并查集初始化的时候father[i] = i;表示一开始自己的父亲是自己(核心)为什么这么初始化,下面你会慢慢了解//初始化const int N = 1001;int father[N];void init(){

数据结构-并查集

并查集是维护集合的数据结构 它支持合并(Union) 查找(Find)功能
首先需要一个father数组(int father[N])存放父亲结点
father[i]表示元素i 的结点的父亲结点
例如 father[1] = 2;表示结点1的父亲结点是2;
在并查集初始化的时候father[i] = i;表示一开始自己的父亲是自己(核心)
为什么这么初始化,下面你会慢慢了解

//初始化
const int N = 1001;
int father[N];
void init(){ 
    for(int i=0;i<N;i++) father[i] = i;
}

并查集其实是一颗多叉树,树中只有一个根节点(即该结点是所有孩子的最终父亲结点),什么是最终的父亲结点,其实很简单,比如father[1] = 2,father[2] = 3,father[3] = 3;这个时候假如求1的最终父亲结点,首先通过father[1] = 2,找到1号结点的父亲结点是2,接下来,再一次找,通过father[2] = 3;此时我们找到2号结点的父亲结点是3,这时候,通过father[3] = 3,找3结点的父亲结点是3,这个是本身,说明自己的父亲是自己(知道为甚一开始初始化了吧),此时的3就就最终父亲结点。话不多说,咱们上代码,代码怎么写呢,好像要一层层的找过去,是不是很像递归函数。。。。
但是,这样确实可以找到最终父亲结点,但是当数据量很大时候,每次都要重新找,是不是时间会超时,如果你懂记忆化搜索的dfs,你就会知道,这里可以用路径压缩来写,不懂也没有事,咱们慢慢学,那么什么是路径压缩,在之前我提过,并查集其实把一个个连通块(不要被连通块这个名词吓怕,连通块就是这些点之前都能够到达,它们在一个集合里面)合起来,它是一颗多叉树,每次查询时候,我们只要找到他的最终父亲结点,所以我们可以直接把自己父亲结点改为根节点(最终结点),是不是就行了,话不多说,上代码。。。

int find_father(int x){ 
	if(father[x]==x){ //递归出口
		return x;
	}
	else{ 
		int temp = find_father(father[x]);
	    father[x] = temp;//路径压缩
	    return temp;
	}
}

下一个环节是并操作(Union)

void Union(int u,int v){ 
	int fu = find_father(u);//找u结点的最终父亲结点
	int fv = find_father(v);//找v结点的最终父亲结点
	if(fu!=fv){ //如果两个连通块不在一个集合,这个时候实施并操作,只要把一个结点作为父亲即可
		father[fu] = fv;
	}
}

看一道题目
链接:https://www.luogu.com.cn/problem/P3367

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000001;
int father[maxn];
void init(int n){ 
	for(int i=1;i<=n;i++) father[i] = i;
}
int find_father(int x){ 
	if(x==father[x]) return x;
	int temp = find_father(father[x]);
	father[x] = temp;
	return temp;
}
void Union(int u,int v){ 
	int fu = find_father(u);
	int fv = find_father(v);
	if(fu!=fv) father[fu] = father[fv];
	
}
int main(){ 
	int n,m,a,b,c;
	cin>>n>>m;
	init(n);
	for(int i=0;i<m;i++){ 
		cin>>a>>b>>c;
		if(a==1) Union(b,c);
		else{ 
			if(find_father(b)==find_father(c)) cout<<"Y"<<endl;
			else cout<<"N"<<endl;
		}
	}
	return 0;
}

注意:找父亲一定要用find_father函数,不能用father数组,为什么呢,那就留给读者自己想想(如果你能想通,说明你已经掌握了)!!完了,撒花,撒花!!

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服