数据结构——并查集

所谓并查集,顾名思义,是一个支持“并”,“查”的集合。

并查集可以想象成一个森林,就是树的集合。

在并查集中,还有一个重要思想:代元法。

其实就是在每一个集合中选一个固定元素,作为集合的代表。

有一种定义方法:用树形数据结构存储数据,树上的每一个节点都是一个元素,树根是代表元素。

但一般来说,我们会维护一个fa数组,fa来保存父节点,根节点的fa是他自己。

在我们初始化一个并查集时,元素的fa都是自己,然后才有get(查找)和merge(合并)操作。

建并查集:

1 int fa[10001];
2 void init()
3 {
4     for(int i=1;i<=10001;i++)
5         fa[i]=i;
6 }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                           路径压缩

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

路径压缩 的思想是,我们只关心每个结点的父结点,而并不太关心树的真正的结构。这样我们在一次查询的时候,可以把查询路径上的所有结点的 father[i]father[i] 都赋值成为根结点。只需要在我们之前的查询函数上面进行很小的改动。

比如说一棵存并查集的树

这就是它的路径压缩,大大的减小了查询复杂度。

接下来我们就来写Get,Merge的模板。

查询(Get)

1 int Get(int x)
2 {
3     if(fa[x]==x)//是树根就返回自己 
4         return x;
5     return fa[x]=Get(fa[x]);//递归查找父亲 
6 }

合并(Merge)

1 void Merge(int x,int y)
2 {
3     fa[Get(x)]=Get(y);//x的树根变成y的树根 
4 }

其实除了并与查之外,还考一个操作:判断两个数是否属于同一集合。

这个就直接用Get函数查找父亲是否相同就可以了。

1 bool Judge(int x,int y)
2 {
3     int a=Get(x),y=Get(y);
4     return a==b;
5 }

其实,这几个模板操作还很容易理解,重在多练,多想。

之后我会再讲解一些习题,来帮助大家深入理解并查集。

我们下次见!

原文地址:https://www.cnblogs.com/sillyben/p/9925213.html