并查集(UNION-FIND)
并查集(Union-Find
Set)是一种用来管理和解决集合分组问题的数据结构,它支持两个操作:
- 查找(Find):查找一个元素属于哪个集合,即找出其所在的连通块。
- 合并(Union):将两个不相交的集合合并成一个新的集合。
并查集模板
查找(Find):这里用树来表示是否属于同一个数组,使用查找(Find)操作返回的是该节点所在树的根节点,如果一个节点x
所在树的根节点就是x
自己,那么findParent(x)
返回的结果就是x
。
合并(Union):合并两个节点x
和y
之前需要先判断x
和y
是否属于一个集合,如果已经在一个集合里,那么直接返回,否则将x
和y
的集合合并(在此实现为将x
和y
的树合并为一个树)。
合并两个集合最原始的方式就是将一个节点的根节点接到另一个节点的根节点上:
其实就是一个树结构,每个节点的祖先节点是其所在的集合,那么就会有一个问题,在最坏的情况下,树会退化为一个链表,这时候的查找时间复杂度为O(N)
,上面的findParent
函数可以在查找过程中将树结构进行压缩,压缩之后的结构如下图所示,每个节点的父亲节点为所在树的根节点:
代码如下:
1 2 3 4 5 6
| int findParent(int x) { if(x != parent[x]) return findParent(parent[x]); return parent[x]; }
|
其查找过程便是压缩过程,见下面的动图:
并查集的模板如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class UF { public: UF(int n) { parent = vector<int>(n); for(int i = 0; i < n; ++i) parent[i] = i; count = n; }
int findParent(int x) { if(x != parent[x]) parent[x] = findParent(parent[x]); return parent[x]; }
void connect(int x, int y) { int parent_x = findParent(x); int parent_y = findParent(y);
if(parent_x == parent_y) return ; --count; parent[parent_y] = parent_x; }
bool isConnected(int x, int y) { return findParent(x) == findParent(y); }
int getCount() { return count; } private: vector<int> parent; int count; };
|
参考:本文中的图引用自labuladong
的算法小抄,模板实现是根据其模板修改而来。