当前位置:   article > 正文

并查集(Union-Find Disjoint Sets)_并查集csdn

并查集csdn

并查集是一种树型的数据结构,主要适用于解决一些元素的分组问题。它管理一系列不相交的集合,并支持两种操作:

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询 两个元素是否在统一个集合中。

概述

在这里插入图片描述

并查集的重要思想在于,用集合中的一个元素代表集合。从上面可以看出,最终得到的是一个树状结构,要寻找集合的元素的代表,只需要一层一层的往上访问父节点,直到找到父节点为自身的根节点。

基本操作

如果共有 n n n个元素,我们可以使用一个数组来存储每个元素的父节点。其代码为:

int[] parent = new int[n];
for (int i = 0; i < len; i++) {
    parent[i] = i;
}
  • 1
  • 2
  • 3
  • 4

查找操作

对于并查集的查找操作,可以用递归的方法实现对代表元素的查询:一层一层的访问父节点,直至根节点。

int find(int v) {
    return v == parent[v] ? v : find(parent[v]);
}
  • 1
  • 2
  • 3

对于两个元素我们可以通过查找操作查找根节点,来判断两个元素是否属于同一个集合。

合并操作

对于合并操作,可以先找到两个集合的代表元素,然后将前者的父节点设置为后者(当然也可以将后者的父节点设置为前者)。

void union(int i, int j) {
    int x = find(i), y = find(j);
    if (x == y) return;
    parent[x] = y;
}
  • 1
  • 2
  • 3
  • 4
  • 5

优化

路径压缩合并

并查集的操作已经完成,但是并查集所形成的树可能是一条单链。对于这样的树越深,我们想要从底部找到根节点会变得越来越难。因此我们可以将一条单链转化为下面的形式:

在这里插入图片描述

上面的实现过程是:在查询的过程中,把沿途的每个节点的父节点都设为根节点即可。

int find(int v) {
    return v == parent[v] ? v : (parent[v] = find(parent[v]));
}
  • 1
  • 2
  • 3

按秩合并

由于上面的路径压缩只在查找元素根节点时起作用,所以加入路径压缩算法之后并查集也不始终都是只有两层树。

在这里插入图片描述

上面两种合并方法,如果可以选择的话我们更希望是后者(即使有路径压缩,但路径压缩也是会消耗时间的),因为后者的合并方法不会使树的深度加深。这样的话可以使用一个数组来记录每个树的深度,合并时比较两个根节点的深度,把深度较小者往较大者上合并。

路径压缩和按秩合并如果一起使用,时间复杂度接近 O ( n ) O(n) O(n)

int[] rank = new int[n];
int[] parent = new int[n];
for (int i = 0; i < len; i++) {
    parent[i] = i;
    rank[i] = 1;
}

void union(int i, int j) {
    int x = find(i), y = find(j);
    if (x == y) return;
    if (rank[x] <= rank[y]) {
        parent[x] = y;
        rank[y] += rank[x];
    } else {
        parent[y] = x;
        rank[x] += rank[y];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

题目链接

  1. 128. 最长连续序列

参考文献:

  1. 算法学习笔记(1) : 并查集
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/836016
推荐阅读
相关标签
  

闽ICP备14008679号