并查集是数据结构中用来表示集合信息的,用以实现确定某个集合含有哪些元素、判断哪些元素属于一个集合,并且求集合中元素的数量等问题。一般我们对集合的操作是通过查找根节点的方法来实现,一般是不断的查找双亲节点直到双亲节点不存在的节点为止,这个节点就是根节点,这个过程的耗费与树高是成正相关的,在进行合并树的时候,如果只是仅仅合并而不采取任何的措施会使得树高不断的增加,查找根节点的耗时也会不断的增加,极端情况就类似于一个单链表。
所以为了避免这种情况,我们在查找某个特定节点的根节点的同时将与根节点之间的所有的节点都直接指向根节点,这个称为路径压缩,完成路径压缩之后,树的形态发生了很大的变化,树高大大降低;
(1)首先我们采用一个数组保存双亲节点,parent[]表示双亲,如果说parent[i]=i,则表示不存在双亲节点,即节点i为其所在树的根节点
(2)不进行路径压缩的查找根节点的递归形式:
int findroot(int x)
{//不带路径压缩的递归查找双亲节点的根节点
if (parent[x] == x)
return x;
else
return findroot(parent[x]);//递归查找其双亲节点的根节点
}
(3)不带路径压缩的非递归查找根节点:
int findroot(int x)
{
int ret;
while (parent[x] != x)
x = parent[x];//当前节点为非根节点则一直查找其双亲节点
ret = x;
return ret;
}
(4)带路径压缩的递归查找根节点:
int findroot(int x)
{
if (parent[x] != x)
parent[x] = findroot(parent[x]);//当前节点的根节点设置成查找返回的根节点的编号
return parent[x];
}
(5)带路径压缩的非递归查找根节点:
int findroot(int x)
{
int ret;
int tmp = x;
while (parent[x] != x)
x = parent[x];
ret = x;//找到根节点保存在ret中
x = tmp;
while (parent[x] != x)
{
int t = parent[x];
parent[x] = ret;//遍历过程中这些结点的双亲节点都设置成已经查找得到的根节点的编号
x = t;
}
return ret;
}
(6)合并两个集合元素:
void merge(int a, int b)/*合并a和b*/
{
a = findroot(a);
b= findroot(b);
if (a != b)
{
parent[a] = b;
//sum[b] += sum[a];/*如果需要统计集合中的元素可以在设置一个sum数组,合并集合中元素个数*/
}
}
(7)在并查集后续讲解中,我们会实现几个例子,来更加清晰的了解并查集!