并查集-UnionFind

少于 1 分钟读完

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。

Union-Find算法有两个操作

Find操作:

确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。

Union操作:

将两个子集合并成同一个集合。

1、Union-Find简单实现

对于一个数组a[N], 用一个辅助数组id[N]表示数组a中每一个元素所属的集合,如果a[i]和a[j]属于同一个集合,那么id[i] = id[j].

//返回元素x所属集合
int find(int a[N], int id[N], int x)
{
	for(int i=0; i<N; i++)
		if(a[i]==x)
			return id[i]
}
//判断两个元素是否属于同一集合
int sameSet(int id[N], int p, int q)
{
	return id[p]==id[q];
}
//合并第p个和第q个元素所属集合
void union(int id[N], int p, int q)
{
	int pid = id[p];
	for(int i=0; i<N; i++)
		if(id[i]==id[q])
			id[i]=pid;
}

2、方法1在union操作时太慢,对每一个集合设置一个root,合并时,只需把一个集合的root作为另一个集合的子节点挂上去。但是这样会生成一棵很高的不平衡的树,导致向上搜索root时时间复杂度太高,加入路径压缩技术(path compression).

//将id数组改成parent数组更形象,返回一个元素所属集合
int root(int parent[N], int i)
{
	while(i!=parent[i])
	{
		parent[i] = parent[parent[i]];//路径压缩
		i = parent[i];
	}
	return i;
}
int sameSet(int parent[N], int p, int q)
{
	return root(parent,p)==root(parent, q);
}

void union(int parent[N], int p, int q)
{
	int proot = root(parent, p);
	int qroot = root(parent, q);
	parent[qroot] = proot;
}

(推荐一个普林斯顿大学的UnionFind算法教程)

留下评论