连接问题
可以非常快的判断网络中节点的连接状态
路径压缩
第一版是用数组实现,第二版虽然也是数组,但是思路是将其想成很多树结构
代码:
public class Main{
private static double testUF(UF uf, int m){
int size = uf.getSize();
Random random = new Random();
long startTime = System.nanoTime();
for (int i = 0; i < m; i ++){
int a = random.nextInt(size);
int b = random.nextInt(size);
uf.unionElements(a, b);
}
for (int i = 0; i < m; i ++){
int a = random.nextInt(size);
int b = random.nextInt(size);
uf.isConnected(a, b);
}
long endTime = System.nanoTime();
return (endTime - startTime) / 1000000000.0;
}
public static void main(String[] args) {
int size = 10000;
int m = 10000;
UninFind1 uf1 = new UninFind1(size);
System.out.println("UninFind1 :" + testUF(uf1, m) + "s");
UninFind2 uf2 = new UninFind2(size);
System.out.println("UninFind2 : " + testUF(uf2, m) + "s");
UnionFind3 uf3 = new UnionFind3(size);
System.out.println("UninFind3 : " + testUF(uf3, m) + "s");
UnionFind4 uf4 = new UnionFind4(size);
System.out.println("UninFind4 : " + testUF(uf4, m) + "s");
UnionFind5 uf5 = new UnionFind5(size);
System.out.println("UninFind5 : " + testUF(uf5, m) + "s");
}
}
接口:
public interface UF{
int getSize();
boolean isConnected(int p, int q);
void unionElements(int p, int q);
}
//quick find 查找很快
public class UnionFind1 implements UF{
private int[] id;
public UnionFind1(int size){
id = new int[size];
for (int i = 0; i < id.length; i ++){
id[i] = i;
}
}
@Override
public int getSize(){
return id.length;
}
//查找元素p所对应的集合编号
private int find(int p){
if (p < 0 && p >= id.length){
throw new IllegalArgumentException("p is out of bound.");
}
return id[p];
}
@Override
public boolean isConnected(int p, int q){
return find(p) == find(q);
}
//合并元素p和元素q所属的集合
@Override
public void unionElements(int p, int q){
int pID = find(p);
int qID = find(q);
if (pID == qID)
return;
for (int i = 0; i < id.length; i ++){
if (id[i] == pID)
id[i] = qID;
}
}
}
//第二种,并很快Union-Find
public class UnionFind2 implements UF{
private int[] parent;
public UnionFind2 (int size){
parent = new int[size];
for (int i = 0; i < size; i ++){
parent[i] = i;
}
}
@Override
public int getSize(){
return parent.length;
}
//查找过程,查找元素p所对应的集合编号
//O(h)复杂度,h为树的高度
private int find(int p){
if (p < 0 && p >= parent.length)
throw new IllegalArgumentException("p is out of bound.");
while (p != parent[p]){
p = parent[p];
}
return p;
}
@Override
public boolean isConnected(int p, int q){
return find(p) == find(q);
}
@Override
public void unionElements(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot){
return;
}
parent[pRoot] = parent[qRoot];
}
}
//第三种 基于size的优化
public class UnionFind3 implements UF {
private int[] parent;
private int[] sz; //sz[i]表示以i为根的集合中元素个数
public UnionFind3 (int size){
parent = new int[size];
for (int i = 0; i < size; i ++){
parent[i] = i;
sz[i] = 1;
}
}
@Override
public int getSize(){
return parent.length;
}
//查找过程,查找元素p所对应的集合编号
//O(h)复杂度,h为树的高度
private int find(int p){
if (p < 0 && p >= parent.length)
throw new IllegalArgumentException("p is out of bound.");
while (p != parent[p]){
p = parent[p];
}
return p;
}
@Override
public boolean isConnected(int p, int q){
return find(p) == find(q);
}
@Override
public void unionElements(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot){
return;
}
//根据两个元素所在的数的元素个数不同判断合并方向
//将元素少的集合合并到元素多的集合上
if (sz[pRoot] < sz[qRoot]){
parent[pRoot] = parent[qRoot];
sz[pRoot] += sz[qRoot];
}else{
parent[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}
}
}
//第四种 基于rank的优化
public class UnionFind4 implements UF {
private int[] parent;
private int[] rank; //rank[i]表示以i为根的集合中元素个数
public UnionFind4 (int size){
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i ++){
parent[i] = i;
rank[i] = 1;
}
}
@Override
public int getSize(){
return parent.length;
}
//查找过程,查找元素p所对应的集合编号
//O(h)复杂度,h为树的高度
private int find(int p){
if (p < 0 && p >= parent.length)
throw new IllegalArgumentException("p is out of bound.");
while (p != parent[p]){
p = parent[p];
}
return p;
}
@Override
public boolean isConnected(int p, int q){
return find(p) == find(q);
}
@Override
public void unionElements(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot){
return;
}
//根据两个元素所在的数的rank不同判断合并方向
//将rank低的集合合并到rank高的集合上
if (rank[pRoot] < rank[qRoot]){
parent[pRoot] = qRoot;
rank[pRoot] += rank[qRoot];
}else if (rank[qRoot] < rank[pRoot]){
parent[qRoot] = pRoot;
}else{
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
}
}
//UnionFind5 添加路径压缩
public class UnionFind5 implements UF {
private int[] parent;
private int[] rank; //rank[i]表示以i为根的集合中元素个数
public UnionFind5 (int size){
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i ++){
parent[i] = i;
rank[i] = 1;
}
}
@Override
public int getSize(){
return parent.length;
}
//查找过程,查找元素p所对应的集合编号
//O(h)复杂度,h为树的高度
private int find(int p){
if (p < 0 && p >= parent.length)
throw new IllegalArgumentException("p is out of bound.");
while (p != parent[p]){
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
@Override
public boolean isConnected(int p, int q){
return find(p) == find(q);
}
@Override
public void unionElements(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot){
return;
}
//根据两个元素所在的数的rank不同判断合并方向
//将rank低的集合合并到rank高的集合上
if (rank[pRoot] < rank[qRoot]){
parent[pRoot] = qRoot;
rank[pRoot] += rank[qRoot];
}else if (rank[qRoot] < rank[pRoot]){
parent[qRoot] = pRoot;
}else{
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
}
}