并查集解决的问题:(速度快)
1.非常快的检查两个元素是否属于一个集合 isSameSet(A, B)
2.将两个元素各自所在的集合,合并在一起 union(A, B) 合并的是A,B所在的 集合,而不是单纯的合并A和B
代表结点:指向自己的结点
初始化时,要有所有的样本结点
2是代表结点
4是代表结点
isSameSet(A, B) 查找A,B的上面的结点,知道找到指向自己的代表结点,如果是同一个代表结点,就是true,否则就是false
union(A, B) 将两个代表结点合并即可,结点数少的挂到结点数多的上面
优化(扁平化处理):当查找,从链上某个结点往上找它的代表结点时,找到之后,沿途所经过的所有结点,在找完之后统统指向代表结点
(只要涉及到链的查找动作时,都优化)
如下面找12结点的代表结点时,

找到代表结点2之后,将12往上的结点统统直接挂到2结点上,但是12结点下面的不管

public class UnionFind {
public class Node{
//随便定义
}
public static class UnionFindSet{
//key为当前结点, value指向父结点
HashMap<Node, Node> fatherMap;
//key为当前结点,value它他连接的结点个数
HashMap<Node, Integer> sizeMap;
//构造器
public UnionFindSet(List<Node> nodes){
fatherMap = new HashMap<>();
sizeMap = new HashMap<>();
for(Node node : nodes){
//初始化的结点的父结点指向自己
fatherMap.put(node, node);
//初始化的结点的结点为1
sizeMap.put(node, 1);
}
}
//找到代表结点,并且将一路上的结点都扁平化(都挂在代表结点上)
public Node findHead(Node node){
Node father = fatherMap.get(node);
if(node != father){
father = findHead(father);
}
fatherMap.put( node, father );
return father;
}
//判断两个结点是否属于同一个集合
public boolean isSameSet(Node node1, Node node2){
return findHead(node1) == findHead(node2);
}
//将两个结点所在的集合合并
public void union(Node node1, Node node2){
Node father1 = findHead(node1);
Node father2 = findHead(node2);
if(father1 != father2){
int size1 = sizeMap.get(father1);
int size2 = sizeMap.get(father2);
if(size1 >= size2){
//当第一个代表结点的size大于第二个代表结点的size时,
// 将第二个代表结点挂在第一个上面,同时更新第一个代表结点的size值
//注意:在fatherMap中,key是结点,value是其前面的结点
fatherMap.put(father2, father1);
sizeMap.put(father1, size1 + size2);
}else{
fatherMap.put(father1, father2);
sizeMap.put(father2, size1 + size2);
}
}
}
}
}