一个可用graph连接表示的array,每个element都代表一个node
常用函数:find(x) && union(x,y)
find(x) 的功能是找出x所对应的root node
union(x,y)的功能是把x和y连在一起,即将y的root node改为x的root node
Quick Find:
把每个element的值设为root node
int find(int x) {
return root[x];
}
void unionSet(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
for (int i = 0; i < root.size(); i++) {
if (root[i] == rootY) {
root[i] = rootX;
}
}
}
}
find(x) -- O(1)
union(x,y) -- O(n)
Quick Union:
把每一个element的值设为parent node
find(x) -- O(n)(最坏情况下是O(n),即每一个node连接上一个node,要traverse n次才能找到root node)
union(x,y) -- O(n) (依然是最坏情况)
Quick Union 比 Quick Find更加efficient,因为我们最常用到的添加关系的function为union,而添加n个元素quick find 需要O(n^2)的time complexity,而 quick union最坏情况下才是O(n^2),大多数时候是<O(n^2)的,所以添加union会更快
Optimization of disjoint set:
- The
find
function – optimized with path compression:
--每次find一个元素的root node时,都会顺便更新往上找的这一条path上所有元素的root node,即如果一个disjoint set是2->3->4->5, find(5)会把2,3,4,5的root node都变为2.
这样可以减少下次用find的时间
实现方式:
int find(int x) {
if (x == root[x]) {
return x;
}
return root[x] = find(root[x]);
}
- The
union
function – Optimized by union by rank: - 把较短的set连到较长的set上去,使得tree的分布最平均。 这样find()的时候需要traverse的element就会变少,time complexity降低
void unionSet(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY]) {
root[rootY] = rootX;
} else if (rank[rootX] < rank[rootY]) {
root[rootX] = rootY;
} else {
root[rootY] = rootX;
rank[rootX] += 1;
}
}
}
Tips:这里的rank代表了height of the tree。 所以当两个height相同的set连在一起,那势必整个tree height至少+1
运用disjoint set:
主功能不变,根据目的增加UnionFind 的函数,或者改变find(),unionSet()一点,例如把void unionSet(x,y)改为bool unionSet(x,y)