1.介绍
并查=合并+查找,集=集合。顾名思义并查集的优点在于将一堆数据按照特定条件分成n个集合,并且能够快速实现查找某一元素属于哪一个集合、将任意两个集合合并的操作。
2.实现方法
第一种实现方法是用最小的元素标记所在集合,此方法不常用,在合并两个集合时需要遍历整个数组,时间复杂度高。
本文重点讲解第二种方法:每一个集合用一棵有根树表示。
1.定义数组a[n]
·初始化数组:每个人都自成一个集合
for (i=1;i<=n;i++)
a[i]=i;
2.判断数组下标与该下标对应的值是否相等
·若a[i]==i,则说明i表示本集合,i是该集合代表,即i是该树的根节点。
·若a[i]==j,则说明j是i的父节点,即j是i的上一级。
a[i] | 1 | 2 | 3 | 2 | 1 | 3 | 4 | 3 | 3 | 4 |
---|---|---|---|---|---|---|---|---|---|---|
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
3.查找与合并操作
(1)查找
int find(int x)
{
if (a[x]==x)
return x;
return a[x]=find(a[x]);
}
这是一种带压缩路径的查找操作,从待查节点开始,一直递归直到找到根节点,再逐步退出来,同时将从根节点到待查节点中间所有节点的数值全部修改为根节点的值。这种方法在当树的深度非常深,且需要多次查找时有显著的优化效果。
(2)合并
void join(int c1,int c2)
{
int f1,f2;
f1=find(c1),f2=find(c2);
if (f1!=f2)
a[c1]=a[c2];
}
以第二个标题“预处理(数组赋值)”中的表格为例,假设要把第二个集合合并到第一个集合中去,只需要将a[2]=2修改为a[2]=1即可,因为第二个集合下面的分支都是指向2,即根节点,因此只需改变根节点的值即可改变整棵树的归属,不用一个一个去修改树中每个节点的值。