并查集:并查集是一种用来管理元素分组情况的数据结构。并查集可以高效地进行如下操作。不过需要注意并查集虽然可以进行合并操作,但是却无法进行分割操作,
1.查询元素a和元素b是否属于同一组
2.合并元素a和元素b所在的组
所以有两个操作,分别是1.判断是否是一个集合,2.合并含有这俩个元素的集合
重点:
- 每一次查找的时候进行优化,就是把每个集合打平,让他们直接和老大相连。
- 两个集合进行合并的时候,小的往大的合并
- 只有老大的size能用到,其他节点的size根本不会用到,所以更新的时候只需要更新老大的。
- 我是采用两个map实现的,一个fathermap一个sizemap
- 并查集必须在初始化的时候就给他所有的数据,开始每一个元素都是一个集合,指向自己
我自己实现的并查集,如果有问题,请参考左神的
public class UnionFindSet {
// 我做的并查集里面放的是Integer类型,类型随意,因为用的map
HashMap<Integer, Integer> fatherMap;
HashMap<Integer, Integer> sizeMap;
public UnionFindSet(int[] list) {
if (list == null || list.length == 0) {
return;
}
for (int temp : list) {
fatherMap.put(temp, temp);
sizeMap.put(temp, 1);
}
}
// 优化过程放在这个函数里面了
public int findHead(int a) {
if (a == fatherMap.get(a)) {
return a;
}
int father = findHead(fatherMap.get(a));
fatherMap.put(a, father);
return father;
}
//上面函数的非递归形式
public int findHeadunrec(int a) {
Stack<Integer> temp=new Stack();
while(a!=fatherMap.get(a)) {
temp.add(a);
a=fatherMap.get(a);
}
while(!temp.isEmpty()) {
int node=temp.pop();
fatherMap.put(node, a);
}
return a;
}
//判断两个元素是否在同一个集合
public boolean isSameSet(int a,int b) {
return fatherMap.get(a)==fatherMap.get(b);
}
//合并集合
public void union(int a,int b) {
//因为我这个int没法为空,所以此处某一个集合为空我就没写,记得是有这个判断的
int fa=fatherMap.get(a);
int fb=fatherMap.get(b);
if(fa!=fb) {
int sizea=sizeMap.get(fa);
int sizeb=sizeMap.get(fb);
if(sizea>=sizeb) {
//a集合的元素多,就把b放进a
fatherMap.put(fa, fb);
sizeMap.put(fb, sizea+sizeb);//更新大小,记住只要跟新头就行,其他以后绝对不可能用到
}else{
fatherMap.put(fb, fa);
sizeMap.put(fa, sizea+sizeb);
}
}
}
}