/**
* 并查集实现
* 时间: 2026/7/27 16:13
*/
public class UFCollection {
public static void main(String[] args) {
int[] nodes = new int[]{10, 20, 30, 40, 50}; //5个节点
int[][] edges = new int[][]{{1, 2}, {2, 3}, {4, 5}}; // 3条边
// 找根节点
int[] parent = calculateParent(nodes, edges);
// 分组多个连通块(同根节点为一块)
Map<Integer, List<Integer>> group = new HashMap<>();
for (int i = 1; i <= nodes.length; i++) {
// 找根节点
int root = find(parent, i);
// 按根节点分组,添加自己
group.computeIfAbsent(root, (key) -> new ArrayList<>()).add(nodes[i - 1]);
}
System.out.println(group);
}
/**
* 计算父节点
*
* @param nodes 节点集合[10,20,30,40,50]
* @param edges 边集合[{1,2},{2,3},{4,5}]
* @return
*/
public static int[] calculateParent(int[] nodes, int[][] edges) {
int n = nodes.length;
// 构造parent[] 记录所有节点的根节点(默认根节点是自己)
int[] parent = new int[n + 1]; // 0位置占位符不用,便于理解
int[] size = new int[n + 1]; // 每棵树的节点数量(默认都是1)
// 初始化
for (int i = 1; i <= n; i++) {
parent[i] = i;
size[i] = 1;
}
// 边并入集合
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
union(parent, size, u, v);
}
return parent;
}
public static void union(int[] parent, int[] size, int u, int v) {
int rU = find(parent, u); // 找根节点
int rV = find(parent, v);
if (rU == rV) {
// 根节点一样(同在一棵树下,无需合并),退出
return;
}
if (size[rU] < size[rV]) { // 找到大树(节点数量大的),进行交换
// 交换后,保证rU是大树(前边点始终保持大树)
int temp = rU;
rU = rV;
rV = temp;
}
// 小树根节点指向为大树
parent[rV] = rU;
// 大树节点数量增加
size[rU] += size[rV];
}
// 查找父节点
public static int find(int[] parent, int x) {
while (parent[x] != x) { //根节点不是自己,继续循环
parent[x] = parent[parent[x]];
x = parent[x];
}
// 根节点是自己,退出循环,说明找到根了
return x;
}
}