数据结构——并查集

并查集

  • 一、介绍
    • 1、初始化
    • 2、查询
    • 3、合并
    • 4、路径压缩(优化方法一)
    • 5、按秩合并(优化方法二)

一、介绍

参考链接:https://zhuanlan.zhihu.com/p/93647900
主要用于解决一些元素分组问题,管理一系列不相交的集合,并支持两种操作:

  • 合并(Union):把两个不相交的集合合并为一个集合;
  • 查询(Find):查询两个元素是否在同一个集合中。

1、初始化

int fa[MAXN];
void init(int n){
	for(int i = 1; i<=n; i++) fa[i] = i;
}

2、查询

一层一层访问父节点,直至根节点。判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。

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

3、合并

先找到两个集合的代表元素,然后将前者的父节点设置为后者。

void merge(int i, int j){
	fa[find[i]] = find[j];
}

4、路径压缩(优化方法一)

把沿途的每个节点的父节点都设为根节点。路径压缩优化后,并查集并不是始终都是一个菊花图(只有两层的树的俗称),由于路径压缩只是在查询时进行,所以并查集最终的结构仍然可能是比较复杂的。

int find(int x){
	if(x == fa[x]) return x;
	else{
		fa[x] = find(fa[x]); //父节点设为根节点
		return fa[x]; //返回父节点
	}
}

以上代码可简写为:

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

5、按秩合并(优化方法二)

把简单的树往复杂的树上合并。(秩不是准确的子树高,而是子树高的上界)
初始化

void init(int n){
	for(int i = 1; i<=n; i++){
		fa[i] = i;
		rank[i] = 1;
	}
}

合并

void merge(int i, int j){
	int x = find(i), y = find(j); //先找到两个根节点
	if(rank[x] <= rank[y]) fa[x] = y;
	else fa[y] = x;
	if(rank[x]==rank[y] && x!=y) rank[y]++; //如果深度相同且根节点不同,则新的根节点的深度+1
}

路径压缩和按秩合并一块使用的话,很可能会破坏rank的准确性。

你可能感兴趣的:(leetcode,c++,数据结构,图论)