1.实现
package leetcode.algo.unionfind;
public class UnionFind {
// 连通分量个数
private int count;
// 存储一棵树
private int[] parent;
// 记录树的“重量”
private int[] size;
public UnionFind(int n) {
this.count = n;
parent = new int[n];
size = new int[n];
for (int i = 0; i < n; i++) {
// 初始化根节点指向自己
parent[i] = i;
size[i] = 1;
}
}
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
return;
}
// 小树接到大树下面,较平衡(这里属于优化逻辑)
if (size[rootP] > size[rootQ]) {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
} else {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
// 判断是否连通
public boolean connected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
return rootP == rootQ;
}
private int find(int x) {
while (parent[x] != x) {
// 进行路径压缩
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public int count() {
return count;
}
}
2. 应用
2.1 有向无环图是否有环?
public boolean containsCircle(int[][] M) {
int n = M.length;
UnionFind uf = new UnionFind(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (M[i][j] == 1) {
if (i !=j && uf.connected(i, j)) {
return true;
}
uf.union(i, j);
}
}
}
return false;
}
public static void main(String[] args) {
int[][] M = {
{1, 1, 0},
{0, 0, 0},
{0, 0, 1}
};
UnionFind uf = new UnionFind(3);
System.out.println(uf.containsCircle(M));
}
2.2 连通分量的数量
public int findCircleNum(int[][] M) {
int n = M.length;
UnionFind uf = new UnionFind(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (M[i][j] == 1) {
uf.union(i, j);
}
}
}
return uf.count();
}
public static void main(String[] args) {
int[][] M = {
{1, 1, 0},
{1, 1, 0},
{0, 0, 1}
};
UnionFind uf = new UnionFind(3);
System.out.println(uf.findCircleNum(M));
}