并查集
并查集
- 并查集也叫作不相交集合(Disjoint Set)
实际上并查集就是用数组来存储树形结构
并查集有2个核心操作
- 查找(Find):查找元素所在的集合(这里的集合并不是特指Set这种数据结构,是指广义的数据集合)
- 合并(Union):将两个元素所在的集合合并为一个集合
有2种常见的实现思路
Quick Find 查找(Find)
操作 查找(Find) 合并(Union) 时间复杂度 O ( 1 ) O ( n ) Quick Union 查找(Find)的时间复杂度: O ( lo g n ) ,可以优化至 O 𝛼 𝑛
合并(Union)的时间复杂度: O ( lo g n ) ,可以优化至 O 𝛼 𝑛, α ( 𝑛 ) < 5 , α ( 𝑛 ) < 5
操作 查找(Find) 合并(Union) 时间复杂度 O ( lo g n ) O ( lo g n )
接口设计
1 |
|
QuickFind
- Quick Find 的 union(v1, v2):让 v1 所在集合的所有元素都指向 v2 的根节点
- 因此需要遍历数组,时间复杂度O(n)
- Find(v)只需O(1)
1 |
|
QuickUnion
- union操作时只是将一侧节点指向另一个节点
- find操作时需要递归向上找到根节点
1 |
|
QuickUnion_S
- 可以看出,在QuickUnion中union操作时固定的将节点接到另一边可能导致树的高度很高,不利于find操作
- 可以根据节点所在集合中元素个数多少来决定将节点接到哪一边
1 |
|
QuickUnion_R
- 和上面的一样,但是根据树的高度进行判断
1 |
|
虽然有了基于rank的优化,树会相对平衡一点
但是随着Union次数的增多,树的高度依然会越来越高 导致find操作变慢,尤其是底层节点(因为find是不断向上找到根节点)
union(1, 5)
- 什么是路径压缩? 在find时使路径上的所有节点都指向根节点,从而降低树的高度
路径压缩
- 路径上的所有节点指向根节点
1 |
|
路径分裂
- 路径分裂:使路径上的每个节点都指向其祖父节点(parent的parent)
1 |
|
路径减半
- 路径减半:使路径上每隔一个节点就指向其祖父节点(parent的parent)
1 |
|
泛型版本
1 |
|
性能测试
- 100_0000数据