在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作:
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
由于支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structure)或合并-查找集合(merge-find set)。其他的重要方法,MakeSet,用于创建单元素集合。有了这些方法,许多经典的划分问题可以被解决。
为了更加精确的定义这些方法,需要定义如何表示集合。一种常用的策略是为每个集合选定一个固定的元素,称为代表,以表示整个集合。接着,Find(x) 返回 x 所属集合的代表,而 Union 使用两个集合的代表作为参数。
说白了,并差集就是看两者是否存在关系,是否在一个集合内,在图里面,常常判断两个点之间是否在一个集合内,是否连通。
并差集的操作,有查找父节点,合并父节点。(这里有路径压缩优化)
判断是否在同一个集合
接下来展示c++的代码
首先 要初始化,每个父亲节点是自己本身。
for(int i=1;i<=n;i++)
fa[i]=i;
初始化完毕后,要查找父亲节点。
int find(int x)
{
if(fa[x]==x)return x;
//如果父亲节点是其本身,说明已经找到父亲节点
else return fa[x]=find(fa[x]);
//对于初学者,这里面是不是有点难理解呢?
//这是个递归的过程,就是递归查找它的父节点是谁
}
并查集森林的两种改进策略:
1. 按秩合并(union by rank)。改进union操作的方法。这种方法的思想是在union操作中使较少节点的树的根指向具有较多节点的树的根,使得总是较小的树成为较大的树的子树。注意,这里并不显式地记录每个节点为根的子树的大小,而是采用一种易于分析的方法。对于每个节点,维护一个秩,它表示该节点高度的一个上界。在使用按秩合并策略的UNION操作中,我们可以让具有较小秩(高度)的根指向具有较大秩的根。我们初始化数组的所有项为-1。下图显示了一棵树及其对于按秩求并的实例。
2. 路径压缩(path compression)。改进find操作的方法。它在查找过程中将查到节点到根的每个节点的父节点直接指向根。如下所示
第一种按秩合并实现代码
rank1[10005];
//要初始化rank1[i]=0;
for(int i=1;i<=n;i++)
rank1[i]=0;
void unit(int x,int y){
x=find(x);
y=find(y);
//先调用find函数,找到父亲节点
if(x==y)return;
//父亲节点相同,说明在一颗树上或者说是在同一个集合内,无需操作
if(rank1[x]<rank1[y])
//x的这棵树高度小于y的高度
fa[x]=y;//将它的父亲点直接改指向y
else{
fa[y]=x;
if(rank1[x]==rank1[y])rank1[x]++;}
}
第二种路径压缩,实现起来比较容易
void unit(int x,int y){
x=find(x);
y=find(y);
if(x!=y)
fa[x]=y;
//完成路径压缩,如果x和y不在同一颗树或者不在一个集合,将x指向y,他们的路径就压缩了
}
//判断x,y是否属于同一集合
bool same(int x,int y)
return find(x)==find(y);
https://blog.youkuaiyun.com/niushuai666/article/details/6662911
这个博客讲的比较通俗生动,如果有兴趣,可以移步这里。
小伙伴们,你是否懂了呢?