印象里大学里面似乎没有讲过这个数据结构。就这个数据结构本身而言,其实是不难的。实际在应用到算法题中的时候,难点在于把实际的问题映射到这种数据结构,如果完成了这种映射,那么,解题就轻而易举了。
最终的并查集的实现,一般只有最经典的一种。
在 理解的过程中,我们可以从第一、第二个版本迭代过去。
版本一
下面是最基础朴素的版本,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
public class UnionFind { private int count; private int[] parent;
public UnionFind(int n) { this.count = n; parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } }
private int find(int x) { while (parent[x] != x) { x = parent[x]; } return x; }
public void union(int p, int q) { int rootP = find(p); int rootQ = find(q); if (rootP == rootQ) { return; } parent[rootP] = rootQ; count--; }
public int count() { return count; }
public boolean connected(int p, int q) { int rootP = find(p); int rootQ = find(q); return rootP == rootQ; } }
|
版本二
下面是有了一点简单的优化的版本,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
public class UnionFind { private int count; private int[] parent; private int[] size;
public UnionFind(int n) { this.count = n; parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; size[i] = 1; } }
private int find(int x) { while (parent[x] != x) { x = parent[x]; } return x; }
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 int count() { return count; }
public boolean connected(int p, int q) { int rootP = find(p); int rootQ = find(q); return rootP == rootQ; } }
|
版本三
下面是使用了路径压缩的版本,那个递归的方法(函数)很简单,但是非常巧妙,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
public class UnionFind { private int count; private int[] parent;
public UnionFind(int n) { this.count = n; parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } }
private int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; }
public void union(int p, int q) { int rootP = find(p); int rootQ = find(q);
if (rootP == rootQ) { return; } parent[rootQ] = rootP;
count--; }
public int count() { return count; }
public boolean connected(int p, int q) { int rootP = find(p); int rootQ = find(q); return rootP == rootQ; } }
|