Princeton-Algorithm-Union Find
该文章为Princeton-Algorithms Part I读书笔记,相关视频在此。
1. 算法用于解决的问题: Dynamic Connectivity
1.1 两个操作:Union & Find
Union & Find关键:ObjectS + Union + Find
1.2 Connected Component
Connected Components2. 实现
2.1 Quick-Find
是一种eager approach,why?
-
思想:利用一个id数组来对每个object进行分类
quick find
Find(p, q): 查看各自的id是否相等
Union(p, q): 将所有与p的id相同的objects的id设置为与q的id相等
-
Java实现
Java 实现 -
效率:Union太慢。一次Union花O(N),连续对M个对象Union耗时O(MN)。
2.2 Quick-Union
是一种lazy approach
-
思想:id数组中存着parent
quick union
Find(p, q): 查看各自的root是否相等
Union(p, q): 将p的root的id设置为q的root的id
-
Java实现
Java实现 -
效率:Union还是太慢,可能花O(N)来find对象的root
效率对比
可以从所维护的树的角度来考虑:
quick find: 树是平的,union之后改动很大
quick union: union虽然只需要对树一次改动,但是可能树很高,find花很长时间
3.优化
3.1 方法1: weighting
-
思想
- 对quick-union进行修改使之避免太高的树
- 记录每个树包含的对象数 (size) Note:也可以是depth,算法complexity上是一样的,但是code不同
- union操作时只将小的树的root连向大的树的root,这样尽量平衡了树,避免了树不断变高。
unweighted vs weigthed
-
Java实现
-
效率: 相当不错,每次union和find都是O(lgN)。连续对N个对象进行M次Union-Find操作耗时O(MlgN)。
效率比较
为什么O(lgN)呢?因为一个节点最大深度只能为lgN
证明:
考虑一个节点x,什么时候深度才会递增1?当它所在的树小于要union的那棵树时。因此union之后,它所在的树的节点数翻倍。由于总节点数为N,因此x所在的树由节点数为1开始,最多能翻倍lgN次,即x的深度最多是lgN。
3.2 方法2:path compression
-
思想:每次利用root(p)找到某个点的root时,再来一次循环将路径上的所有点都指向root,进而又减少了树的高度!
-
效率:非常好。In theory, 连续对M个对象进行N次Union-Find操作的amortized的时间复杂度为O(MlgN)。In pratical, 其实甚至接近了线性耗时O(N).
union find优化效率
4. 应用
4.1 Percolation穿透问题
percolation model具有NXN的区域,每个单元格有一定的概率要么空,要么填充。问题是求解是否上边能穿透到下底。
更实际的应用有电路问题,流水问题,社交问题等
percolation application此外,还有一个关于如何得到percolation threshold(穿透阈值)的实验:
estimate percolation threshold算法的发展思路技巧:引入上下两个virtual site便于check是否上边与下底相连