CS61B:并查集

并查集

  • 介绍并查集基本概念
  • 实现并查集基本算法
  • 实现的算法中采用了两种优化
    • 路径压缩:在 find 操作中,通过将路径上所有节点直接连接到根节点,极大地减少了树的高度,从而优化了后续操作的时间复杂度。
    • 按大小合并:在 union 操作中,将较小集合的根节点连接到较大集合的根节点,从而保持树的平衡,避免退化成链表。

并查集基本概念

并查集(Union-Find)是一种数据结构,用于处理不相交集合(Disjoint Sets)的合并和查询操作。它非常适合解决动态连通性问题,例如在图论中判断两个节点是否属于同一个连通分量。并查集的主要操作有两个:查找(Find)和合并(Union)。

核心操作

  1. 查找(Find)

    • 查找元素所属集合的代表(根节点)。这一操作通常用于判断两个元素是否属于同一个集合。
    • 使用路径压缩优化:在查找的过程中,将路径上的所有节点直接连接到根节点,从而降低树的高度,提高后续操作的效率。
  2. 合并(Union)

    • 将两个不相交的集合合并为一个集合。
    • 使用按秩合并(union by rank)或按大小合并(union by size)优化:将较小集合的根节点连接到较大集合的根节点,保持树的平衡,避免退化成链表。

实现细节

并查集通常使用一个数组来实现,数组中的每个元素表示一个节点,值表示该节点的父节点。如果某个元素是根节点,则其值为负数,表示集合的大小(按大小合并)或秩(按秩合并)。

主要方法

  • 初始化:创建一个并查集,其中每个元素单独作为一个集合。
  • 查找(Find):找到元素所属集合的根节点,并进行路径压缩。
  • 合并(Union):将两个集合合并,并进行按秩或按大小合并。
  • 连接检查(isConnected):检查两个元素是否在同一个集合中。
  • 集合大小(sizeOf):返回某个元素所属集合的大小。

代码示例

以下是一个典型的并查集实现,包含路径压缩和按大小合并:

package union;

public class UnionFind {

    private int[] parent;

    // Creates a UnionFind data structure holding n vertices. Initially, all vertices are in disjoint sets.
    public UnionFind(int n) {
        parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = -1;
        }
    }

    // Throws an exception if v1 is not a valid index.
    public void validate(int v1) {
        if (v1 < 0 || v1 >= parent.length) {
            throw new IndexOutOfBoundsException("Index " + v1 + " is not valid.");
        }
    }

    // Returns the size of the set v1 belongs to
    public int sizeOf(int v1) {
        validate(v1);
        int root = find(v1);
        return -parent[root];
    }

    // Returns the parent of v1. If v1 is the root of a tree, returns the negative size of the tree for which v1 is the root.
    public int parent(int v1) {
        validate(v1);
        return parent[v1];
    }

    // Returns true if nodes v1 and v2 are connected.
    public boolean isConnected(int v1, int v2) {
        validate(v1);
        validate(v2);
        return find(v1) == find(v2);
    }

    /**
     * Connects two elements v1 and v2 together. v1 and v2 can be any valid elements, and a union-by-size heuristic is used.
     * If the sizes of the sets are equal, tie break by connecting v1’s root to v2’s root.
     * Unioning a vertex with itself or vertices that are already connected should not change the sets,
     * but it may alter the internal structure of the data structure.
     */
    public void union(int v1, int v2) {
        validate(v1);
        validate(v2);
        int root1 = find(v1);
        int root2 = find(v2);

        if (root1 == root2) {
            return; // v1 and v2 are already in the same set
        }

        int size1 = -parent[root1];
        int size2 = -parent[root2];

        if (size1 <= size2) {
            parent[root1] = root2;
            parent[root2] = -(size1 + size2);
        } else {
            parent[root2] = root1;
            parent[root1] = -(size1 + size2);
        }
    }

    // Returns the root of the set v1 belongs to. Path-compression is employed allowing for fast search-time.
    public int find(int v1) {
        validate(v1);
        if (parent[v1] < 0) {
            return v1;
        }
        parent[v1] = find(parent[v1]); // Path compression
        return parent[v1];
    }
}

并查集的应用

并查集广泛应用于图论和网络连接等领域,包括:

  • 判断图中是否存在环
  • 查找最小生成树(Kruskal算法)
  • 网络连接问题
  • 社交网络中的社团检测

并查集以其高效的操作和易于实现的特性,成为解决连通性问题的常用工具。

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

poison_Program

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值