Union-Find note

152 阅读2分钟

Dynamic Connectivity

建模:

  • 数组索引作为不同的对象
  • 相互连接的对象的最大集合为一个 Connected component

操作:

  • Find query 检查两个对象是否位于同一个 component 中
  • Union command 并集替换掉包含这两个对象的 components (两堆合并为一堆)

API: image.png

Quik Find

数据结构:

  • 长度为 N 的整型数组 id[ ]
  • 当且仅当 p 和 q 有同样的 id 时,它们是连接中的

Find:检查 p 和 q 是否有同样的 id

Union:合并分别包含 p 和 q 的 component,即 将所有id等于 id[p] 的对象的id 改为 id[q]

分析:在 quick-find 中,每次find()只访问数组一次,union()的访问次数介于 (N+3)(两次索引查找,递归N次,一次赋值) 到 (2N+1) (两次索引查找,递归N次,N-1次索引查找赋值)

缺陷:Union()操作过于昂贵,如果解决Dynamic Connectivity问题且最后只有一个component,那么总共至少(N-1)(N+3)次数组访问,平方级别。

Quik Union

数据结构:

  • 长度为 N 的整型数组 id[ ]
  • 当且仅当 p 和 q 有同样的 id 时,它们是连接中的
  • p 的根为 id[id[id[...id[p]...]]]

Find:检查 p 和 q 是否有同样的根

Union:合并分别包含 p 和 q 的 component 时,将 p 的根 指向 q 的根

image.png

缺陷:find()的性能取决于树的深度。树可能变得很深,导致find()变得昂贵。

Quik-Union Improvements

Improvement 1: weighting

思想:

  • 从 quick-union 改进,避免出现过深的树
  • 跟踪每一个树的规模
  • 链接时做一个判断,即 将更小规模的树 链接到 更深的树的根上,而不是反过来

Find:检查 p 和 q 是否有同样的根

Union:合并分别包含 p 和 q 的 component 时,先对两个对象所在的树深度进行比较,将 规模更小 的树 连向 规模更大 的树的根

image.png

特点:

  • 任意节点的深度最大只有 lgN

Improvement 2: path compression

思想:

  • 在计算 p 的根之后,将 p 的id指向该根,以压缩路径

image.png

一个改进 quik-union 为 压缩路径形式的例子:

image.png

image.png

Union-Find Applications

一个例子:Percolation

建模:

  • 拥有 N*N 方格的矩形区域
  • 每个方格以概率 p 打开,1-p 关闭
  • 整个系统 Percolation 当且仅当矩形的顶部和底部通过 open sites 连接

image.png

要讨论的问题:在不同的 p 值下,整个系统 Percolation 的可能性。

image.png

Solution: run simulations to try and determine the value of the p

实操:

  • 初始化一个 N*N 数量的对象,从 0 ~ N²-1 命名
  • 创建两个虚拟节点来模拟 root
  • 逐步 open 方格直到顶部与底部连接
  • 计算频率 来估计 p

image.png