DisjointSet 并查集

并查集

拥有nn个元素的集合s=[x0,x1,x2,,xn1]s = [ x_0, x_1, x_2, \cdots , x_{n-1} ]分为两个家庭。每个家族只有唯一一个祖先,相同家庭的元素拥有相同的祖先。因此集合ss中的每个元素的祖先只有22种可能。并查集是一种适合元素分类的高效树形数据结构,支持快速分类和查询。

father(x)father(x)xx的父节点,设ancestor(x)ancestor(x)xx的祖先节点。当father(x)=xfather(x) = x时称xx为祖先节点。

对于拥有1010个成员的集合s=[0,1,2,3,4,5,6,7,8,9]s = [ 0,1,2,3,4,5,6,7,8,9 ],将其分成两个家庭AABB。初始时令每个成员的父亲都是自己,如图所示:

当声明22个成员xix_ixjx_jxixjx_i \le x_j)属于同一家庭,令xix_i的节点祖先为xjx_j的父亲(也可以反过来),即father(xj)=ancestor(xi)father(x_j) = ancestor(x_i)。这样的操作会使元素xjx_j更接近祖先节点,从而缩短了递归向上查找的路径长度,该操作也称为压缩路径。

下面对上图中的集合ss进行具体演示:

(1)(1)声明0044属于同一家庭,设置father(4)=ancestor(0)=0father(4) = ancestor(0) = 0

(2)(2)声明1199节点属于同一家庭,设置father(9)=ancestor(1)=1father(9) = ancestor(1) = 1

(3)(3)声明0022节点属于同一家庭,设置father(2)=ancestor(0)=0father(2) = ancestor(0) = 0

(4)(4)声明1133节点属于同一家庭,设置father(3)=ancestor(1)=1father(3) = ancestor(1) = 1

(5)(5)声明3355节点属于同一家庭,设置father(5)=ancestor(3)=1father(5) = ancestor(3) = 1

(6)(6)声明6688节点属于同一家庭,设置father(8)=ancestor(6)=6father(8) = ancestor(6) = 6

(7)(7)声明2266节点属于同一家庭,设置father(6)=ancestor(2)=0father(6) = ancestor(2) = 0

(8)(8)声明1177节点属于同一家庭,设置father(7)=ancestor(1)=1father(7) = ancestor(1) = 1

合并两节点xxyy时,根据固定规则设置father(y)=ancestor(x)father(y) = ancestor(x)(或者相反);查询节点xx的祖宗节点时,若father(x)ancestor(x)father(x) \neq ancestor(x)则设置father(x)=ancestor(x)father(x) = ancestor(x)。并查集的分类、查询操作的时间复杂度接近O(1)O(1)

源码

DisjointSet.h

DisjointSet.cpp

测试

DisjointSetTest.cpp

Last updated