您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java实现数据结构中的并查集
## 一、并查集概述
### 1.1 什么是并查集
并查集(Disjoint Set Union,简称DSU)是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。它支持以下两种主要操作:
- **Find**:查找元素所属集合的代表元素
- **Union**:合并两个集合
并查集在解决连通性问题、图论算法(如Kruskal最小生成树算法)以及网络连接问题中有着广泛的应用。
### 1.2 基本概念
- **父节点表示法**:每个节点记录其父节点,根节点指向自己
- **路径压缩**:优化查找操作的技巧
- **按秩合并**:优化合并操作的策略
## 二、并查集的基本实现
### 2.1 基础数据结构
```java
public class UnionFind {
private int[] parent; // 父节点数组
// 构造函数,初始化n个元素的并查集
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i; // 初始时每个元素自成一派
}
}
}
查找操作有两种实现方式:普通查找和路径压缩优化。
public int find(int x) {
while (parent[x] != x) {
x = parent[x];
}
return x;
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
合并操作也有两种实现方式:普通合并和按秩合并优化。
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX;
}
}
public class UnionFind {
private int[] parent;
private int[] rank; // 秩数组
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1; // 初始高度为1
}
}
public void union(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]++;
}
}
}
操作类型 | 普通实现 | 路径压缩 | 按秩合并 | 两者结合 |
---|---|---|---|---|
Find | O(n) | O(α(n)) | O(log n) | O(α(n)) |
Union | O(n) | O(α(n)) | O(log n) | O(α(n)) |
其中α(n)是反阿克曼函数,增长极其缓慢,可以认为是常数时间。
题目描述:有n个人,给出m对朋友关系,朋友的朋友也是朋友,求有多少个朋友圈。
public int findCircleNum(int[][] M) {
int n = M.length;
UnionFind uf = new UnionFind(n);
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (M[i][j] == 1) {
uf.union(i, j);
}
}
}
int count = 0;
for (int i = 0; i < n; i++) {
if (uf.find(i) == i) {
count++;
}
}
return count;
}
题目描述:给定一个m×n的空白网格,逐步添加陆地,要求每次添加后返回当前岛屿数量。
public List<Integer> numIslands2(int m, int n, int[][] positions) {
UnionFind uf = new UnionFind(m * n);
int[][] dirs = {{0,1}, {1,0}, {-1,0}, {0,-1}};
List<Integer> res = new ArrayList<>();
int count = 0;
for (int[] pos : positions) {
int x = pos[0], y = pos[1];
int id = x * n + y;
if (uf.parent[id] != -1) { // 已处理过
res.add(count);
continue;
}
uf.parent[id] = id;
count++;
for (int[] dir : dirs) {
int nx = x + dir[0], ny = y + dir[1];
int nid = nx * n + ny;
if (nx >= 0 && nx < m && ny >= 0 && ny < n && uf.parent[nid] != -1) {
if (uf.union(id, nid)) {
count--;
}
}
}
res.add(count);
}
return res;
}
可以维护节点到根节点的距离信息,解决如食物链等问题。
class WeightedUnionFind {
private int[] parent;
private int[] weight; // 到父节点的权重
public WeightedUnionFind(int n) {
parent = new int[n];
weight = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
if (parent[x] != x) {
int origin = parent[x];
parent[x] = find(parent[x]);
weight[x] += weight[origin];
}
return parent[x];
}
public boolean union(int x, int y, int value) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return weight[x] - weight[y] == value;
}
parent[rootX] = rootY;
weight[rootX] = weight[y] - weight[x] + value;
return true;
}
}
使用主席树技术实现可回退的并查集,适用于需要保存历史状态的场景。
/**
* 优化版并查集实现
*/
public class OptimizedUnionFind {
private final int[] parent;
private final int[] rank;
private int count; // 连通分量数量
public OptimizedUnionFind(int n) {
parent = new int[n];
rank = new int[n];
count = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
// 路径压缩
while (parent[x] != x) {
parent[x] = parent[parent[x]]; // 路径压缩
x = parent[x];
}
return x;
}
public boolean union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) return false;
// 按秩合并
if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
rank[rootX] += rank[rootY];
} else {
parent[rootX] = rootY;
rank[rootY] += rank[rootX];
}
count--;
return true;
}
public boolean isConnected(int x, int y) {
return find(x) == find(y);
}
public int getCount() {
return count;
}
}
并查集是一种高效处理不相交集合问题的数据结构,通过路径压缩和按秩合并优化,可以达到接近常数时间复杂度。Java实现时需要注意:
未来发展方向包括: - 分布式并查集实现 - GPU加速的并行化处理 - 与机器学习结合的新型应用场景
掌握并查集不仅能解决特定算法问题,更能培养抽象数据结构的思维模式,是每个Java开发者应当熟练掌握的基础数据结构之一。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。