并查集
在一些应用中我们会对一堆元素进行分组,每一个小组是一个不相交的集合。然后我们会根据需要查找某一个元素属于那个集合,或者是将某两个元素所在的集合按照一定要求进行合并。就好比朋友圈一样:A 与 B 原本不认识,各自有各自的朋友圈。但是有一天偶然之间 A 与 B 朋友圈里的一位朋友 C 在聚会时认识了。C:“回头我介绍我的大哥 B 给你认识吧”,随后 A 和 B 都带着自己的小弟们碰面了。于是AB两个朋友圈合二为一了。
给他们六个依次编号为1~6,用一个数组 array[] 来记录他们的关系,数组的下标 i 表示第 i 个人,array[i] 表示 i 的父亲,如果 i 为根的话,则 array[i] 为负,array[i] 的绝对值表示以该节点为根的树总共拥有的节点个数:
整个变化过程 首先是找各自的 root (find(A),find(B)),然后就是合并两个集合 union(A,B)。很形象称为并查集。使用代码实现并查集:
public class UnionFindSet {
private List<Integer> set;
public UnionFindSet(){
set = new ArrayList<>(16);
}
public UnionFindSet(int size){
set = new ArrayList<>(size);
}
/**
* 查找元素编号为 index 的集合根。
* @param index
* @return
*/
public int findRoot(int index){
while (set.get(index)>=0){
index = set.get(index);
}
// 采用路经压缩
// if (set.get(index)<0) return index;
// if (set.get(index)>=0)
// set.set(index,findRoot(set.get(index)));
// return set.get(index);
return index;
}
/**
* 合并 a,b 所在集合
* @param a
* @param b
* @return
*/
public boolean union(int a,int b){
int aRoot = findRoot(a);
int bRoot = findRoot(b);
if (aRoot==bRoot) return false;
set.set(aRoot,set.get(aRoot)+set.get(bRoot));
set.set(bRoot,aRoot);
return true;
}
}