前言:
目录
并查集的原理
并查集(Disjoint-Set Data Structure)是一种用于管理集合的高效数据结构,特别适用于处理“动态连接”的问题,即动态地合并集合或查询两个元素是否属于同一个集合。并查集在计算机科学中有着广泛的应用,如用于解决最小生成树问题(Prim算法和Kruskal算法)、解决网络连通性问题、解决图论中的问题等。
并查集的基本操作
并查集主要支持以下三种基本操作:
实现方式
并查集有两种常见的实现方式:路径压缩和按秩合并。
C++实现
#include <iostream>
#include <vector>
class UnionFind {
private:
std::vector<int> parent;
std::vector<int> 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 <stdio.h>
#include <stdlib.h>
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语言的实现,我们可以看到并查集的基本操作和逻辑在不同语言中的实现方式。这两种语言的实现都遵循了并查集的核心思想,即通过查找和合并操作来管理集合,以高效地处理动态连接问题。