Union-Find
问题描述:
给定一个n个序列的对象,有两种操作:
-Union command:连接两个对象;
-Find/connected query:两个对象是否连接(有路径)
算法实现方式
1.用一个数组保存着每个对象所在的connected component,这种方式可以快速进行FIND,但是在union操作时需要遍历整个对象数组
2.利用树的观点,在数组中保存每个对象节点的parent,这个每个connected component就是一棵树,这种方式union很高效,只需要更新相应节点的parent即可,但是在find的时候可能就会遍历整个树,特别是当一棵树比较高的时候。
3.在上述2中实现union(p,q)的时候,我们用一种特定的方式将p所在的树的置为q所在树的孩子,没有考虑到树的大小,就会导致严重失衡的情况。Weighted quick-union 引入一个新的数组来保存每棵树的尺寸,总是将小树链入到大树下,实现相对的平衡。
4.利用path compression进一步对上述算法进行优化,在每一次root操作的时候,不单单只是追溯查询一个节点的根,而是动态的将其根节点往上推进。从而使得 component tree 越来越平坦化。 如下要查询节点6的根节点,在查询的最后会更新6直接指向根节点。
接下来会把3,1分别指针指向root
具体代码
--------1
//这种方式可以快速判断是否相连,但是union操作需要遍历整个对象数组
public
class
QuickFindUF {
// 这个数组保存着这个N个节点的所在分组
private
int
[]
id
;
public
QuickFindUF(
int
n) {
id
=
new
int
[n];
for
(
int
i = 0; i < n; i ++) {
id
[ i] = i ;
}
}
public
boolean
find(
int
p,
int
q) {
return
id
[p] ==
id
[q];
}
// 连接p,q节点的时候,要将p所在component中的所有节点的id更新
public
void
union(
int
p,
int
q) {
int
pid =
id
[p];
int
qid =
id
[q];
for
(
int
i = 0; i <
id
.
length
; i++) {