并查集是1964年别人脑补的一个算法,到证明结束是1989年,这个证明也是够漫长的。
并查集的效率非常高,当有N个数据的时候,假设查询次数到了N之后,其时间复杂度仅为O(1)!!
并查集使用哈希是来做的,所以节点中并不需要放些什么。FatherMap中key 是当前节点,value是当前节点的父节点。然后是sizeMap,key是当前节点,value是点当前节点的所在集合的节点总个数。
getHeadNode:获取当前节点的头节点,为了提高之后的效率,每次获取都将不与头节点相连的节点改为与头节点直接相连(也就是所谓的路径压缩了),整个过程由递归来解决,可以节省很多代码,当然,也可以自己压栈
union:将两个节点所在的集合 合并。将节点数少的哪一个集合 合并到节点数多的那个集合的头节点,然后除了节点数多的那个头节点需要更换size之外,别的节点不需要更改,因为以后再也不会使用到了。
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
public class C03_UnionFind {
public static class Node{
//写什么都行
}
public static class unionFind{
private HashMap<Node, Node>fatherMap;
private HashMap<Node, Integer>sizeMap;
public unionFind(){//构造
fatherMap = new HashMap<Node, Node>();
sizeMap = new HashMap<Node, Integer>();
}
//获取头节点(递归版)
public Node getHeadNode(Node cur){
Node fatherNode = fatherMap.get(cur);
if(cur!=fatherNode){
cur = fatherNode;
fatherNode = fatherMap.get(cur);
getHeadNode(cur);
}
return fatherNode;
}
//获取头节点(非递归版)
public Node getHeadNode2(Node node){
Stack<Node>stack = new Stack<Node>();
Node cur = node;
Node fatherNode = fatherMap.get(cur);
//将除头节点以外的节点压进栈里
while(fatherNode != cur){
stack.push(cur);
cur = fatherNode;
fatherNode = fatherMap.get(cur);
}
//到这里fatherNode就是头节点了
//出栈,并且将节点都指向头节点
while(!stack.isEmpty()){
fatherMap.put(stack.pop(), fatherNode);
}
return fatherNode;
}
//合并两个节点所在的集
public void union(Node n1,Node n2){
if(n1==null || n2==null){
return ;
}
Node head1 = getHeadNode(n1);
Node head2 = getHeadNode(n2);
if(head1 == head2){
return ;
}
if(sizeMap.get(head1)>sizeMap.get(head2)){
//head1的个数多就将head2接到head1上
//只需要改变head1的size,因为他的子节点已经不需要用到size了
fatherMap.put(head2, head1);
sizeMap.put(head1, sizeMap.get(head1)+sizeMap.get(head1));
}else {
fatherMap.put(head1, head1);
sizeMap.put(head2, sizeMap.get(head1)+sizeMap.get(head2));
}
}
//两个节点是否来自同一个集合,只看他们的头是否一样
public boolean isSameSet(Node n1,Node n2){
return getHeadNode(n1)==getHeadNode(n2);
}
//初始化
public void init(List<Node>nodes){
fatherMap.clear();
sizeMap.clear();
for (Node node : nodes) {
sizeMap.put(node, 1);
fatherMap.put(node, node);
}
}
}
public static void main(String[] args) {
}
}