什么是并查集
并查集(Union Find)是一种用于管理分组的数据结构。
对于一组数据,主要支持两个动作:
- union(p,q)
- isConnected(p,q)
对于并查集,我们设计一个interfaceUF来看两个元素是否所属一个集合(是否连接的),以及合并两个元素。
public interface UF {
int getSize();
boolean isConnected(int p, int q);
void unionElements(int p, int q);
}
对于并查集,像线段树那样,并不添加或删除某个元素,只是查和并的操作。
Quick Find(第一版并查集)
使用数组进行模拟并查集的操作。
package 并查集;
/**
* 描述 第一版并查集
* Quick Find下的Union时间复杂度是O(n)
*
* @author lixinzhen
* @create 2021/11/10 21:01
*/
public class UnionFind1 implements UF {
private int[] id;
public UnionFind1(int size) {
id = new int[size];
for (int i = 0; i < id.length; i++) {
id[i] = i;
}
}
@Override
public int getSize() {
return id.length;
}
//查找元素p所对应的集合编号
private int find(int p) {
if (p < 0 && p >= id.length)
throw new IllegalArgumentException("p is out of bound");
return id[p];
}
//查看元素p和元素q是否所属一个集合(时间复杂度为O(1))
@Override
public boolean isConnected(int p, int q) {
return find(p) == find(q);
}
//合并元素p和元素q所属的集合(时间复杂度为O(n))
@Override
public void unionElements(int p, int q) {
int pID = find(p);
int qID = find(q);
if (pID == qID)
return;
for (int i = 0; i < id.length; i++) {
if (id[i] == pID)
id[i] = qID;
}
}
}
Quick Union(第二版并查集)
将每一个元素,看作一个节点,由子节点指向父节点。
初始情况下这个森林有10个树,每个树读只有一个节点。
假设union6,5,那么6指向5
查询和合并的时间复杂度都是树的高度。
package 并查集;
/**
* 描述 第二版并查集
*
* @author lixinzhen
* @create 2021/11/10 21:33
*/
public class UnionFind2 implements UF {
private int[] parent;
public UnionFind2(int size) {
parent = new int[size];
for (int i = 0; i < parent.length; i++) {
parent[i] = i;//每个节点指向自己,独立的树
}
}
@Override
public int getSize() {
return parent.length;
}
//查找过程,查找元素p对应的集合编号
//O(h)复杂度,h为树的高度
private int find(int p) {
if (p < 0 && p >= parent.length)
throw new IllegalArgumentException("p is out of bound");
while (p != parent[p])
p = parent[p];
return p;
}
//查看元素p和元素q是否所属一个集合
//O(h)复杂度,h为树的高度
@Override
public boolean isConnected(int p, int q) {
return find(p) == find(q);
}
//合并元素p和元素q所属的集合
//O(h)复杂度,h为树的高度
@Override
public void unionElements(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot)
return;
parent[pRoot] = qRoot;
}
}