Union Find
动态连通性
有 N 个对象,对象之间可以连通。那么这 N 个对象就可能形成 M 个集合。
我们继续假设: “相连(is connected to)” 是两个数之间的一种关系,且这种关系满足以下条件:
-
自反性(Reflexive): p 和 p 是相连的;
-
对称性(Symmetric): 如果 p 和 q 是相连的,那么 q 和 p 也是相连的;
-
传递性(Transitive): 如果 p 和 q 相连且 q 和 r 相连,那么 p 和 r 相连。
当两个数相连时,它们属于同一个
等价类(Connected Components)。等价类,就是所有相连的数的集合,这个集合必须包含所有相连的数。
ConnectedComponents
对于这些对象,有两个操作
- Union(x, y)可以连接两者
- Find(x)来查询对象 x 属于哪个集合
并查集
Quick Find 算法
- 整数型数组 id[],长度为 N。
- p 和 q 是相连的等价于数组中 p 下标和 q 下标的数相同。
|
|
算法分析
QuickFind 算法太慢了。 下表是最坏情况下 QuickFind 算法对一组点操作使用的时间消耗。
| 算法 | 初始化 | union 操作 | find 操作 |
|---|---|---|---|
| QuickFind | N | N | 1 |
Union 操作过于缓慢:如果要对 N 对点进行 union 操作,最多需要对数组访问 N^2 次。
Quick Union 算法
- 整数型数组 id[],长度为 N。
- id[i]中存储 i 的父节点( 也就是形成一个链接,直到其父节点就是它自己,说明到头了)
- i 的根节点(root)是 id[id[id[id[…id[i]…]]]]
QuickUnion
|
|
算法分析
对一对点进行操作需要访问数组的次数,图中是最坏情况。
| 算法 | 初始化 | union 操作 | find 操作 |
|---|---|---|---|
| QuickFind | N | N | 1 |
| QuickUnion | N | N* | 1 |
*:包括了寻找根节点的操作。
QuickFind 的缺点
- Union 操作太慢了,最差为 N
- 树是平的,但是维护这个状态时间耗费太大了
QuickUnion 的缺点
- 树可能会很高
- Find 操作太慢了,最差为 N
算法优化
加权 Weighting
加权 QuickUnion(Weighted QuickUnion)
- 改进 QuickUnion,避免太高的树
- 对每个树的大小(包含点的数量)进行记录
- union 操作时,比较两个点所在树的大小,小数的根节点连接到大树的根节点之上
路径压缩 Path Compressing
在计算点 p 的根节点 root 之后,每个经过的节点,如果其根节点不为 root 的话,让其根节点变成 root,如图是带路径压缩的 QuickUnion 算法(Quick Union with Path Compression),下图是具体的过程。
优化后的代码
|
|
算法分析
使用带路径压缩的加权 Quick Union 算法,对于 N 个数,M 次操作时,访问数组次数最多为 c (N + M lg* N)。 (c 为常数, lg* N 是 lg(lg(lg(…lg()…)))。)
对于 N 个数,M 次操作时,有没有线性访问数组次数的算法呢?
- 理论上, WQUPC(Weighted Quick Union & Path Compression)不是线性的
- 实际中,WQUPC 基本是线性的
现已证明,没有完全的线性算法存在的
参考资料
原理解析
动态连通性
有N个对象,对象之间可以连通。那么这N个对象就可能形成M个集合。
我们继续假设: “相连(is connected to)” 是两个数之间的一种关系,且这种关系满足以下条件:
-
自反性(Reflexive): p和p是相连的;
-
对称性(Symmetric): 如果p和q是相连的,那么q和p也是相连的;
-
传递性(Transitive): 如果p和q相连且q和r相连,那么p和r相连。
当两个数相连时,它们属于同一个
等价类(Connected Components)。等价类,就是所有相连的数的集合,这个集合必须包含所有相连的数。
ConnectedComponents
对于这些对象,有两个操作
- Union(x, y)可以连接两者
- Find(x)来查询对象x属于哪个集合
并查集
Quick Find算法
- 整数型数组id[],长度为N。
- p和q是相连的等价于数组中p下标和q下标的数相同。
|
|
算法分析
QuickFind算法太慢了。 下表是最坏情况下QuickFind算法对一组点操作使用的时间消耗。
| 算法 | 初始化 | union操作 | find操作 |
|---|---|---|---|
| QuickFind | N | N | 1 |
Union操作过于缓慢:如果要对N对点进行union操作,最多需要对数组访问N^2次。
Quick Union算法
- 整数型数组id[],长度为N。
- id[i]中存储i的父节点( 也就是形成一个链接,直到其父节点就是它自己,说明到头了)
- i的根节点(root)是id[id[id[id[…id[i]…]]]]
QuickUnion
|
|
算法分析
对一对点进行操作需要访问数组的次数,图中是最坏情况。
| 算法 | 初始化 | union操作 | find操作 |
|---|---|---|---|
| QuickFind | N | N | 1 |
| QuickUnion | N | N* | 1 |
*:包括了寻找根节点的操作。
QuickFind的缺点
- Union操作太慢了,最差为N
- 树是平的,但是维护这个状态时间耗费太大了
QuickUnion的缺点
- 树可能会很高
- Find操作太慢了,最差为N
算法优化
加权 Weighting
加权QuickUnion(Weighted QuickUnion)
- 改进QuickUnion,避免太高的树
- 对每个树的大小(包含点的数量)进行记录
- union操作时,比较两个点所在树的大小,小数的根节点连接到大树的根节点之上
路径压缩 Path Compressing
在计算点p的根节点root之后,每个经过的节点,如果其根节点不为root的话,让其根节点变成root,如图是带路径压缩的QuickUnion算法(Quick Union with Path Compression),下图是具体的过程。
优化后的代码
|
|
算法分析
使用带路径压缩的加权Quick Union算法,对于N个数,M次操作时,访问数组次数最多为c (N + M lg* N)。 (c为常数, lg* N是lg(lg(lg(…lg()…)))。)
对于N个数,M次操作时,有没有线性访问数组次数的算法呢?
- 理论上, WQUPC(Weighted Quick Union & Path Compression)不是线性的
- 实际中,WQUPC基本是线性的
现已证明,没有完全的线性算法存在的
具体题目
261 Graph Valid Tree
305 Number of Islands II
- Islands are popping out of a grid sea. Give number of islands after each popping.
- Maintain a parent set, do erase and insert during each union.
323 Number of Connected Components in an Undirected Graph
547 Friend Circles
721 Accounts Merge
785 Is Graph Bipartite?
- For each node, merge all adjacent nodes. Then check for each edge.
803 Bricks Falling When Hit
- Reverse-time union-find.
947 Most Stones Removed with Same Row or Column
- Given stones on a 2D plane, one can remove a stone if there are other stones sharing the same row or column. Find maximum removes.
- Union points by row or column.
952 Largest Component Size by Common Factor
- Find the largest connected component of a graph, where there is an edge if two nodes share a common factor > 1.
- O(N*sqrt(W)) time, where W is the maximum value in input array.
990 Satisfiability of Equality Equations
Reference
-
No backlinks found.