并查集
连续两天遇到并查集的问题,还是认真的看了下并查集的相关资料,再此总结一下:
什么是并查集:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。常常在使用中以森林来表示。 进行快速规整。
主要操作的解释及代码:
1、 初始树的建立,每个元素的父节点指向它本身
void Init_Set(int x)
{
root[x] = x;
rank[x] = 0;
}
2、 查找一个元素所在的集合,找到这个元素所在集合的根节点,判断两个元素是否属于同一集合,只要看他们所在集合的根节点是否相同即可。
int Find_Set(int x)
{
if(x != root[x])
root[x] = Find_Set(root[x]);// 递归实现路径压缩
return root[x];
}
bool IsSame_Set(int x, int y)
{
return Find_Set(x) == Find_Set(y) ? true : false;
}
3、 合并两个不相交集合,找到其中一个集合根节点编号,将另外一个集合的根节点的父亲指向它。
(a)图为两个不相交集合,(b)图为合并后Father(b):=Father(g)
void Union_Set(int x, int y)
{
x = Find_Set(x);
y = Find_Set(y);
if (x == y) return;
if(rank[x] > rank[y])
root[y] = x;
else if(rank[x] == rank[y])
{
rank[x]++;
root[y] = x;
}
else
root[x] = y;
}
并查集的优化:
(1)路径压缩
寻找根节点时采用递归,但是一旦元素一多起来,或退化成一条链,每次Find_Set都将会使用O(n)的复杂度,这显然不是我们想要的。对此,我们必须要进行路径压缩,即我们找到根节点时“顺便”把它的子孙直接连接到它上面,这就是路径压缩了。路径压缩后,查找的复杂的就变为O(1)了。
(2)rank合并
合并时将元素少的集合合并到元素多的集合中。
图摘自CLRS: