1. 并查集:支持两个集合合并,两个是否一个集合。让两个操作几乎都是O(1)<br /> 如果使用链表 合并是O(1) 查询是否一个集合就不是了,使用hash 查询是O(1),合并就不是了。<br />使用往上值的图的方式:<br /> 看两个是否一个集合:指针一直往上指,指到不能再指了,看是否同一个代表元素,是就是同一集合,否则不是。<br /> 两个集合合并:当两个不是集合的情况都是自己指自己,改变某个顶指针,指向另外一个。 <br /> 当两个是集合时候,数量少的顶部连向数量多的顶部。<br /> 关键是往上指到不能再指了,这个过程如果链条过长会达到瓶颈,所以当指到不能再指的时候将沿途的节点都指向最上面的。
    1. // 样本会进来包一层,叫做元素
    2. public static class Node<V> {
    3. V value;
    4. public Node(V v) {
    5. value = v;
    6. }
    7. }
    8. // 并查集结构
    9. public static class UnionFind<V> {
    10. // 包一层 a对应a圈
    11. public HashMap<V, Node<V>> nodes;
    12. // key 某个元素,value指该元素的父 。 小弟 大哥
    13. public HashMap<Node<V>, Node<V>> parents;
    14. // key 某个集合的代表元素 ,value 该集合的大小,包含一个顶点和有多少小弟
    15. public HashMap<Node<V>, Integer> sizeMap;
    16. public UnionFind(List<V> values) {
    17. nodes = new HashMap<>();
    18. parents = new HashMap<>();
    19. sizeMap = new HashMap<>();
    20. for (V cur : values) {
    21. Node<V> node = new Node<>(cur);// 包层圈
    22. nodes.put(cur, node); // 自己对应自己的圈
    23. parents.put(node, node); // 小弟 大哥 都是自己
    24. sizeMap.put(node, 1);// 自己是光杆大哥
    25. }
    26. }
    27. // 给一个节点,往上到不能再往上,把顶点返回
    28. public Node<V> findHead(Node<V> cur) {
    29. Stack<Node<V>> path = new Stack<>();
    30. // 不是顶点的时候
    31. while (cur != parents.get(cur)) {
    32. // 沿途节点加入栈
    33. path.push(cur);
    34. // 获得最顶点
    35. cur = parents.get(cur);
    36. }
    37. while (!path.isEmpty()) {
    38. // 将这条链上的father全都改成cur,扁平化
    39. parents.put(path.pop(), cur);
    40. }
    41. return cur;
    42. }
    43. // 是否一个集合
    44. public boolean isSameSet(V a, V b) {
    45. // 是否初始化
    46. if(nodes.containsKey(a)&& nodes.containsKey(b)){
    47. // 是不是同一个顶点
    48. return findHead(nodes.get(a)) == findHead(nodes.get(b));
    49. }
    50. return false;
    51. }
    52. // 合并
    53. public void union(V a, V b) {
    54. if(nodes.containsKey(a)&& nodes.containsKey(b)){
    55. // 找到各自顶点
    56. Node<V> aHead = findHead(nodes.get(a));
    57. Node<V> bHead = findHead(nodes.get(b));
    58. if (aHead != bHead) {
    59. int aSetSize = sizeMap.get(aHead);
    60. int bSetSize = sizeMap.get(bHead);
    61. // 设置数量多和数量少的集合顶点
    62. Node<V> big = aSetSize >= bSetSize ? aHead : bHead;
    63. Node<V> small = big == aHead ? bHead : aHead;
    64. // 挂载
    65. parents.put(small, big);
    66. // 更改合并完大小
    67. sizeMap.put(big, aSetSize + bSetSize);
    68. // 删除之前的顶点,因为合并了。
    69. sizeMap.remove(small);
    70. }
    71. }
    72. }
    73. public int sets() {
    74. return sizeMap.size();
    75. }
    76. }