关于并查集的概念和效率,这里不详述,网上一大堆,这里主要记录一下并查集的 Java代码实现
三步走:
1.初始化pres和rangks数组,pres为每个元素的父结点(上一级),ranks为每个元素作为根节点时的树的秩(树的深度),一开始设置pres的每个值为每个元素自己,设置ranks每个值为0.
2.find() 查询该元素的首级,顺便做路径压缩
3.unionSet() 合并两个集合,按秩合并,秩小的树的根节点指向秩大的树的根节点。
//Java实现的并查集数据结构和并查算法
public class 并查集 {
public static void main(String[] args) {
int n = 10; //结点数
//边数据
int[][] edges = {{0, 9}, {9, 3}, {1, 2}, {2, 8}, {4, 5}, {6, 7}, {0, 5}, {6, 8}};
int[] pres = new int[n];
int[] ranks = new int[n];
//初始化,把pres每个元素的上一级设置为自己,把ranks的每个元素的深度设置为0
for (int i = 0; i < n; i++) {
pres[i] = i;
ranks[i] = 0;
}
//通过边数据构造并查集
for (int[] edge : edges)
unionSet(edge[0], edge[1], pres, ranks);
printAns(pres, ranks);
}
//并:合并两个集合,按秩合并
public static void unionSet(int n1, int n2, int[] pres, int[] ranks) {
int root1 = find(n1, pres);
int root2 = find(n2, pres);
if (ranks[root1] < ranks[root2]) {
pres[root1] = root2;
} else {
pres[root2] = root1;
if (ranks[root1] == ranks[root2])
ranks[root1]++;
}
}
//查:查找元素的首级
public static int find(int x, int[] pres) {
int root = x;
while (pres[root] != root)
root = pres[root];
//路径压缩
int p = x;
while (pres[p] != p) {
int t = pres[p];
pres[p] = root;
p = t;
}
return root;
}
public static void printAns(int[] pres, int[] ranks) {
System.out.print("pres:\t");
for (int pre : pres)
System.out.print(pre + " ");
System.out.print("\nranks:\t");
for (int rank : ranks)
System.out.print(rank + " ");
System.out.print("\nidx:\t");
for (int i = 0; i < pres.length; i++)
System.out.print(i + " ");
}
}
/*
* pres: 0 6 1 0 0 4 6 6 1 0
* ranks:2 1 0 0 1 0 2 0 0 0
* idx: 0 1 2 3 4 5 6 7 8 9
*
* */