一. 认识并查集
- 可以高效的解决连接问题(Connectivity Problem)
- 检查网络中节点间的连接状态(网络是个抽象概念:用户之间形成的网络)
- 数学中的集合类实现(合并问题)
- 连接问题和路径问题:连接问题只需回答是或否,而路径问题要回答出具体的路径;
- 对于一组数据,并查集主要支持三个动作:
- union(p, q) -----------------并操作,将元素p,q并入同一个组内
- find(p)------------------------查操作,返回元素所在组号,通常是一个private的辅助函数
- isConnected(p, q)---------查操作,查询元素p,q是否在一个组内(同一个组内的元素是相互连接的)
二.并查集的实现
1. Quick Find并查集:
基本数据表示:
- 并查集内部实际是存储了一个数组,数组的索引(id)表示元素的编号(这里的元素可以是各种类型),索引存储的值表示该元素所属的集合,而属于同一集合的元素即是连接起来的元素(下图,id为0,2,4,6,8的元素同属于集合0,是连接起来的)。
- Quick Find并查集,实现一个了一个find函数,用来支持快速查询操作,查询操作时间复杂度为O(1), 合并操作时间复杂度为O(n);
package UFs;
import UnionFind.UnionFind;
public class quickFindUF implements UnionFind {
//维护一个数组,数组的索引表示不同的元素(元素可以是各种类型),索引所对应的值表示该索引所属的集合
private int[] id;
public quickFindUF(int size){
id = new int[size];
//初始化每个元素都属于不同的集合
for(int i=0; i<id.length; i++){
id[i] = i;
}
}
@Override
public int size(){
return id.length;
}
//查看p元素和q元素是否属于同一个集合
@Override
public boolean isConnected(int p, int q){
return id[p] == id[q];
}
//合并p元素和q元素所属集合
@Override
public void unionElements(int p, int q){
int pUnion = id[p];
int qUnion = id[q];
if(pUnion == qUnion){
return;
}
for(int i=0; i<id.length; i++){
if(id[i] == pUnion){
id[i] = qUnion;
}
}
}
}
2. Quick Union并查集:
基本数据表示:
- 将每一个元素,看作是一个节点,是一种奇怪的树结构,是由孩子节点指向父亲节点
- 根节点的指针指向自己,合并两个元素,就是将其中一个元素的根节点指向另一个元素的根节点