/*
并查集是由一组不相交的集合组成的高级数据结构
每个集合内的元素之间存在着某种我们关心的关系
通常我们用于一个元素来代表这个集合,我们称其为代表元
对于我们关心的关系,它通常是某种等价关系,但实际我们可以
应用到更泛的关系上。
并查集支持的操作有查找某个元素属于哪个集合和合并两个不相交集合
具体实现有链表实现和有根树实现,这里指讨论有根树的实现
用有根树来实现并查集,一课有根树即代表一个集合,其中树根作为集合的代表元
树中的每个节点代表集合的一个元素;
定义节点的高度为该节点到叶子节点的简单路径的最长路径的边数
初始化:开始时每个元素都看做一个集合,其代表元即该节点本身
查找操作:我们要查找某个元素属于哪个集合,只需找到其所在集合的代表元,也就是树根,所以实现很简单,只需一趟,沿着其父亲一直向上寻找,知道某个节点的父亲是其本身。在这里我们采取启发式策略,利用“路径压缩”的方式使有根树尽量”矮“(显然这会
加快后续查找操作)
合并操作:合并两个集合,只需将一个树的根指向另一个树的根,这里同样采取启发式策略对其优化,还是建立在使树越矮的思路上,防止所谓的树“退化现象”,如果不进行有效的限制那么会出现一棵树越高的情况,”按秩合并“可以满足我们的要求,能在合并的时
候使新的树尽量的矮,这里的秩(rank)是指节点高度的上界,而不是树所含节点的个数,算法导论上说是为了简化分析。具体在合并时,分两种情况
如果两个节点的秩不相等则把秩大的点作为秩小的点的根,如果相等,则任意把一个节点作为另一个节点
的根,并将作为新根的节点的秩加1
具体代码实现:(采用了按秩合并和路径压缩)
查找:
递归实现
int find(int x)
{
if (x!=p[x])
p[x]=find(p[x]);
return p[x];
}
非递归实现
int find(int x)
{
//
}
合并:
void union(int x,int y)
{
if (find(x)!=find(y))
{
a=find(x);
b=find(y);
if (rank[a]>rank[b])
{
fa[b]=a;
}
else fa[a]=b;
if (rank[a]==rank[b])
++rank[b];
}
}
*/