mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-31 19:13:42 +00:00
Update 算法 - 并查集.md
重新绘制 Quick Union 树结构配图;调整 Quick Union 与加权合并的原理说明,补充路径压缩实现代码及复杂度分析。
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 86 KiB |
+24
-6
@@ -13,7 +13,7 @@
|
||||
|
||||
## 前言
|
||||
|
||||
用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
|
||||
并查集(Union-Find)用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。
|
||||
|
||||
<div align="center"> <img src="pics/uf-intro.png" width="600px"/> </div><br>
|
||||
|
||||
@@ -94,7 +94,7 @@ public class QuickFindUF extends UF {
|
||||
|
||||
可以快速进行 union 操作,只需要修改一个节点的 id 值即可。
|
||||
|
||||
但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一直向上查找操作,直到找到最上层的节点。
|
||||
这种方法把每个连通分量看成一棵树:id[p] 保存的是 p 的父节点,根节点的 id 等于它自身。同一个连通分量的节点 id 值不一定相同,但根节点相同,因此 find 需要沿着 id 一直向上查找,直到找到根节点,开销较大。
|
||||
|
||||
<div align="center"> <img src="pics/uf-quick-union.png" width="520px"/> </div><br>
|
||||
|
||||
@@ -133,16 +133,16 @@ public class QuickUnionUF extends UF {
|
||||
|
||||
## 加权 Quick Union
|
||||
|
||||
为了解决 quick-union 的树通常会很高的问题,加权 quick-union 在 union 操作时会让较小的树连接到较大的树上面。
|
||||
为了解决 Quick Union 的树通常会很高的问题,加权 Quick Union 在 union 操作时会让节点较少的树连接到节点较多的树上面。
|
||||
|
||||
理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。
|
||||
这样构造的树深度最多不超过 logN。这是因为一个节点的深度只在它所在的树连接到另一棵树上时加 1,而那棵树的节点数不少于它,合并后的树至少是原来的两倍大;N 个节点的树最多只能翻倍 logN 次。
|
||||
|
||||
<div align="center"> <img src="pics/uf-weighted.png" width="760px"/> </div><br>
|
||||
|
||||
```java
|
||||
public class WeightedQuickUnionUF extends UF {
|
||||
|
||||
// 保存节点的数量信息
|
||||
// 以该节点为根的树的节点数,只有根节点的值有意义
|
||||
private int[] sz;
|
||||
|
||||
|
||||
@@ -189,6 +189,24 @@ public class WeightedQuickUnionUF extends UF {
|
||||
|
||||
<div align="center"> <img src="pics/uf-path-compression.png" width="640px"/> </div><br>
|
||||
|
||||
```java
|
||||
@Override
|
||||
public int find(int p) {
|
||||
int root = p;
|
||||
while (root != id[root]) {
|
||||
root = id[root];
|
||||
}
|
||||
while (p != root) { // 把路径上的节点直接链接到根节点
|
||||
int next = id[p];
|
||||
id[p] = root;
|
||||
p = next;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
```
|
||||
|
||||
这样处理后,一组 union 和 find 操作的均摊代价非常接近 1(与反阿克曼函数 α(N) 成正比,实际中 α(N) 不超过 4),但单次操作在最坏情况下仍与 logN 成正比。
|
||||
|
||||
## 比较
|
||||
|
||||
| 算法 | union | find |
|
||||
@@ -196,7 +214,7 @@ public class WeightedQuickUnionUF extends UF {
|
||||
| Quick Find | N | 1 |
|
||||
| Quick Union | 树高 | 树高 |
|
||||
| 加权 Quick Union | logN | logN |
|
||||
| 路径压缩的加权 Quick Union | 非常接近 1 | 非常接近 1 |
|
||||
| 路径压缩的加权 Quick Union | 均摊非常接近 1 | 均摊非常接近 1 |
|
||||
|
||||
## 参考资料
|
||||
|
||||
|
||||
Reference in New Issue
Block a user