【高阶数据结构】——并查集:高效地管理集合

前言:

前面我们已经学习了简单的数据结构,包括栈与队列、二叉树、红黑树等等,今天我们继续数据结构的学习,但是难度上会逐渐增大,在高阶数据结构中我们要学习的重点是图等

目录

并查集的原理

并查集的基本操作

实现方式

C++实现

C语言实现


并查集的原理

并查集(Disjoint-Set Data Structure)是一种用于管理集合的高效数据结构,特别适用于处理“动态连接”的问题,即动态地合并集合或查询两个元素是否属于同一个集合。并查集在计算机科学中有着广泛的应用,如用于解决最小生成树问题(Prim算法和Kruskal算法)、解决网络连通性问题、解决图论中的问题等。

并查集的基本操作

并查集主要支持以下三种基本操作:

  1. 查找(Find):确定一个元素属于哪个集合。
  2. 合并(Union):将两个集合合并为一个集合。
  3. 初始化(Init):为每个元素创建一个独立的集合。

实现方式

并查集有两种常见的实现方式:路径压缩和按秩合并。

  • 路径压缩:在查找操作中,将查找路径上的所有节点的父节点直接指向根节点,以减少查找路径的深度。
  • 按秩合并:在合并操作中,将秩较小的集合合并到秩较大的集合中,以减少树的高度。

C++实现

#include 
#include 

class UnionFind {
private:
    std::vector parent;
    std::vector rank;

public:
    UnionFind(int n) : parent(n), rank(n) {
        for (int i = 0; i < n; ++i) {
            parent[i] = i;
            rank[i] = 1;
        }
    }

    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]); // 路径压缩
        }
        return parent[x];
    }

    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX == rootY) return;

        if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else {
            parent[rootY] = rootX;
            rank[rootX] += 1;
        }
    }

    bool connected(int x, int y) {
        return find(x) == find(y);
    }
};

int main() {
    int n, m;
    std::cin >> n >> m;
    UnionFind uf(n);
    for (int i = 0; i < m; ++i) {
        int a, b;
        std::cin >> a >> b;
        uf.unite(a - 1, b - 1); // 转换为0-based索引
    }
    for (int i = 0; i < m; ++i) {
        int a, b;
        std::cin >> a >> b;
        std::cout << (uf.connected(a - 1, b - 1) ? "YES" : "NO") << std::endl;
    }
    return 0;
}

C语言实现

#include 
#include 

typedef struct {
    int parent[10001];
    int rank[10001];
} UnionFind;

void init(UnionFind *uf, int n) {
    for (int i = 0; i <= n; ++i) {
        uf->parent[i] = i;
        uf->rank[i] = 1;
    }
}

int find(UnionFind *uf, int x) {
    if (uf->parent[x] != x) {
        uf->parent[x] = find(uf, uf->parent[x]); // 路径压缩
    }
    return uf->parent[x];
}

void unite(UnionFind *uf, int x, int y) {
    int rootX = find(uf, x);
    int rootY = find(uf, y);
    if (rootX == rootY) return;

    if (uf->rank[rootX] > uf->rank[rootY]) {
        uf->parent[rootY] = rootX;
    } else if (uf->rank[rootX] < uf->rank[rootY]) {
        uf->parent[rootX] = rootY;
    } else {
        uf->parent[rootY] = rootX;
        uf->rank[rootX] += 1;
    }
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    UnionFind uf;
    init(&uf, n);
    for (int i = 0; i < m; ++i) {
        int a, b;
        scanf("%d %d", &a, &b);
        unite(&uf, a - 1, b - 1); // 转换为0-based索引
    }
    for (int i = 0; i < m; ++i) {
        int a, b;
        scanf("%d %d", &a, &b);
        if (find(&uf, a - 1) == find(&uf, b - 1)) {
            printf("YES\\n");
        } else {
            printf("NO\\n");
        }
    }
    return 0;
}

通过上述C++和C语言的实现,我们可以看到并查集的基本操作和逻辑在不同语言中的实现方式。这两种语言的实现都遵循了并查集的核心思想,即通过查找和合并操作来管理集合,以高效地处理动态连接问题。

你可能感兴趣的:(数据结构,算法,学习,c++)