并查集理论篇

102 阅读3分钟

并查集就是多个不同的集合,因为集合中某两个集合产生联系,两个集合就合并为同一个集合。

对于集合中的每一个元素都有其对应的下标和编号(所有的编号都初始化为-1,表示每个数都是独立的一个集合):

image.png

怎么建立编号?

一.通过数组a传进来,放到vetcor里面,就有了对应的编号

二.通过map建立映射:

image.png image.png

假如0,1,2分别是不同集合的头节点,它们的集合成员分别是{6,7,8},{4,9},{3,5}: 物理图形如下:

image.png 逻辑图像如下: image.png 我们拿图(1-1)的(a)集合来解释一下图(1-2)。

刚开始下标0对应的编号是-1,然后0变为了图(1-1)中集合(a)的root节点。此时它的孩子节点有{6,7,8},其中{6,7,8}对应的编号分别都是{-1,-1,-1}。0节点作为它们的parent节点就把它们的编号全部吸收了。所以0节点的编号变为了-1,而{6,7,8}节点作为0节点的孩子节点,它们要存放自己父节点之前的下标,以确保可以找到parent,所有{6,7,8}对应的编号存的分别是{0,0,0};

合并图(1-1)中(a),(b)两个集合

假如现在节点7和节点8产生了联系,那么就要把节点7,8所在的集合合并为一个集合,合并之后如下所示:

image.png

逻辑图像如下:

image.png

我们发现下标为0的节点对应的编号是-7,而整棵树刚好就有7个节点。下标为2的节点对应的编号是-3,以2为parent的集合刚好就有3个节点。

对此我们可以总结出来经验,经验如下:

一个节点的编号是负数,那么它就是树、子树的根,它的编号的绝对值就是整棵树/子树的节点个数
二。一个节点对应的编号是正数,那么这个编号存的就是其父亲节点的下标

模拟实现并查集

我们此次模拟用vector建立编号: image.png

构造 vector的构造方式之一:前n个元素全部初始化为-1,即刚开始所有节点编号都为-1,表示刚开始都是独立的集合:

image.png 一个并查集的主要函数有以下几部分:

一.我们要合并集合,但是合并的时候需要判断对方是否为根,不是根就去找它的根,找到了合并到它的根下。

二·如果和对方本身就是一个集合,那再合并就没有意义了,所以要判断是否和对方处于一个集合。 image.png

找根

观察下图,假如下标为9的节点就是x,它的编号>=0,那么它肯定不是根节点,观察集合(a)可以看出来。

当一个节点的编号为正数时,那么编号一定存的是其父节点的下标(上文总结/或观察集合(a)也可看出)。

此时我们就跳到它的父节点处,即跳到了下标为1的节点处。我们发现该节点的编号值仍然是大于等于0,所以接着跳,跳到了下标为0的节点处。

此时我们发现该节点的编号值<=0,所以就找到了x节点的根节点。

image.png

code

image.png

合并集合

合并之后parent加上children的编号之和children存储parent的indeximage.png image.png

判断是否在一个集合

两个集合是同一个根就是在一个集合:

image.png

统计集合的个数

有多少个根就有多少个集合:

image.png

代码托管:模拟并查集/并查集.txt (gitee.com)

我们可以用我们上面模拟实现的并查集写一道题:Leetcode LCR 116. 省份数量 并查集 - 掘金 (juejin.cn)