并查集基础概念与代码实现
并查集:
每个集都有一个节点作为该集合的代表,查两元素是否属于同个集合,只需对两元素顺着parent指针往上找,找到某节点其parent指针指向自己时停止,对比两元素的找到节点,如相同则两元素属于同个集合。
关键点:查询集合代表点且查到时,不着急返回该代表点,而是将沿途查上来的节点的parent指针修改为直接指向该集合代表点。
Union(A,B):A和B所在的集合合并。该操作会包含isSameSet操作。如不在同集合内,将大小较小的集合挂在较大的集合底下。
用并查集的前提:提前知道所有元素,将所有元素各自成一个集合
时间复杂度:不是每次查询的代价是O(1),而是查询次数很高或者合并次数很高时的平均代价会是O(1)
基础内容转载:https://zhuanlan.zhihu.com/p/93647900/
具体Code实现:
public static class node { } public static class UCS//Union checking set并查集 { public HashMap<node, node>father;//存储父节点,key的父节点是value public HashMap<node, Integer>rank;//存储集合代表点所代表的集合的数量,非集合代表点对应的value忽视 public UCS() { father = new HashMap<Union.node, Union.node>(); rank = new HashMap<Union.node, Integer>(); } public void makeset(List<node>nodesList) { //初始化数据,将数据打入哈希表中 father.clear(); rank.clear(); for (node node : nodesList) { father.put(node, node); rank.put(node, 1); } } public node findFather(node n) { node F = father.get(n); if(F!=n) F = findFather(F);//往上寻找 father.put(n, F);//把沿途的节点的父都直接指向找到的代表点F return F; } public void union(node a,node b) { if(a==null||b==null) return ; node aF = findFather(a); node bF = findFather(b); if(aF!=bF) { //对比两集合的大小,将小集合挂在大集合的代表点下,更新对应rank int aRank = rank.get(aF); int bRank = rank.get(bF); if(aRank<=bRank) { father.put(aF, bF); rank.put(bF, aRank+bRank); } else { father.put(bF, aF); rank.put(aF, aRank+bRank); } } } }