并查集的结构实现,对外提供两个方法:
1.检查两个元素是否属于一个集合
2.将两个元素所在的集合合并在一起
下面这个图是并查集的结构类似图,就是一颗多叉树
public static class UnionFindSetr{
private HashMap<node,node> fatherMap;//前面的node就是某一个结点,后面的node就是这个结点的父节点
private HashMap<node,Integer> sizeMap;//某一个结点他所在的集合有多少个结点。integer代表的是node所在的集合的属性。
public UnionFindSetr(LinkedList<node> nodes){
fatherMap = new HashMap<node,node>();
sizeMap = new HashMap<node,Integer>();
makeSet(nodes);
}
private void makeSet(LinkedList<node> nodes) {
for (node node : nodes) {//刚开始是每一个点自己成为一个集合
fatherMap.put(node, node);
sizeMap.put(node, 1);
}
}
//找头,给一个元素把他的代表结点返回,并且在这个过程中把链压缩变扁平。递归
private node getHead(node node) {
node father = fatherMap.get(node);
if(father != node) {
father = getHead(father);
}
return father;
}
//找头,给一个元素把他的代表结点返回,并且在这个过程中把链压缩变扁平。非递归
private node getHead1(node node) {
Stack<node> stack = new Stack<node>();
node cur = node;
node parent = fatherMap.get(cur);
while(cur != parent) {
stack.push(cur);//每次压入当前的结点
cur = parent;
parent = fatherMap.get(cur);
}
while(!stack.isEmpty()) {
fatherMap.put(stack.pop(), parent);
}
return parent;
}
//判断两个结点是不是同一个集合,只需要比较他们的集合的代表结点是不是同一个
public boolean isSameSet(node a ,node b) {
return getHead(a) == getHead(b);
}
//将两个元素所在的集合合并在一起,我们规定小的往大的上面挂(这个是随便的看自己的定义了)
public void union(node a,node b) {
if(a == null && b == null) {
return ;
}
node aHead = fatherMap.get(a);
node bHead = fatherMap.get(b);
if(aHead != bHead) {
int aSetSize = sizeMap.get(aHead);
int bSetSize = sizeMap.get(bHead);
if(aSetSize <= bSetSize) {
fatherMap.put(aHead, bHead);
sizeMap.put(bHead, aSetSize + bSetSize);
}else {
fatherMap.put(bHead, aHead);
sizeMap.put(aHead, aSetSize + bSetSize);
}
}
}
}
下面是一个大佬总结的并查集基础用法,引用一下
https://blog.csdn.net/xianpingping/article/details/80011187
结论:一共的数据样本假设有n个,可以随意的查两个元素在一个集合,也可以任意的把两个元素所在的集合合并,只要查询次数+合并次数整体逼近了O(N)及以上,那么单次的操作不管查询还是合并的平均时间复杂度都是O(1)。