并查集
拥有n个元素的集合s=[x0,x1,x2,⋯,xn−1]分为两个家庭。每个家族只有唯一一个祖先,相同家庭的元素拥有相同的祖先。因此集合s中的每个元素的祖先只有2种可能。并查集是一种适合元素分类的高效树形数据结构,支持快速分类和查询。
设father(x)为x的父节点,设ancestor(x)为x的祖先节点。当father(x)=x时称x为祖先节点。
对于拥有10个成员的集合s=[0,1,2,3,4,5,6,7,8,9],将其分成两个家庭A和B。初始时令每个成员的父亲都是自己,如图所示:
当声明2个成员xi和xj(xi≤xj)属于同一家庭,令xi的节点祖先为xj的父亲(也可以反过来),即father(xj)=ancestor(xi)。这样的操作会使元素xj更接近祖先节点,从而缩短了递归向上查找的路径长度,该操作也称为压缩路径。
下面对上图中的集合s进行具体演示:
(1)声明0和4属于同一家庭,设置father(4)=ancestor(0)=0;
(2)声明1和9节点属于同一家庭,设置father(9)=ancestor(1)=1;
(3)声明0和2节点属于同一家庭,设置father(2)=ancestor(0)=0;
(4)声明1和3节点属于同一家庭,设置father(3)=ancestor(1)=1;
(5)声明3和5节点属于同一家庭,设置father(5)=ancestor(3)=1;
(6)声明6和8节点属于同一家庭,设置father(8)=ancestor(6)=6;
(7)声明2和6节点属于同一家庭,设置father(6)=ancestor(2)=0;
(8)声明1和7节点属于同一家庭,设置father(7)=ancestor(1)=1;
合并两节点x和y时,根据固定规则设置father(y)=ancestor(x)(或者相反);查询节点x的祖宗节点时,若father(x)=ancestor(x)则设置father(x)=ancestor(x)。并查集的分类、查询操作的时间复杂度接近O(1)。
源码
DisjointSet.h
DisjointSet.cpp
测试
DisjointSetTest.cpp