在近乎O(1)的时间复杂度下支持两个操作:
- 将两个集合合并
- 询问两个元素是否在一个集合中
基本原理:
每个集合用一棵树维护,根节点的编号是整个集合的编号,
对于每一个点都存储父节点,p[x]表示父节点
,若想确定某个点属于哪一个集合,就先确定这个点的父节点,知道找到树根位置,根节点编号即数组编号。
- 如何判断树根: p[x] = x
- 如何求x的集合编号
while(p[x] != x)
x = p[x];
- 如何合并两个集合:若px是x的集合编号,py是y的集合编号,p[x] = py;
相当于把x的根节点变成y的根节点的一个child
优化:
路径压缩: 一个点找到根节点后,把这个点所经过路径上的所有点都指向根节点。
- 返回x所在集合编号 + 路径压缩
int find(int x)
{
if(p[x] != x) p[x] = find{p[x]);
return p[x];
}