算法——Union-find算法(并查集)

1. 动态连通性

引出问题:问题的输入是一个整数对,其中每个整数都表示一个某种类型的对象,一对整数p、q可以理解为“p q是相连的”。我们假设“相连”是一种等价关系,这也意味着它具有:

  • 自反性:p和q是互连的;
  • 对称性:如果p、q是相连的,那么p、q也是相连的;
  • 传递性:如果p和q是相连的且q和r是相连的,那么q和r也是相连的。

等价关系能够将对象分为多个等价类。在这里,当且仅当两个对象相连时他们才属于同一个等价类。我们需要设计一个数据结构来保存程序已知的所有整数对的足够多的信息,并用他们来判断一对新对象是否是互联的。我们将这个问题通俗的叫做动态连通性问题。以下举一些常见的列子:

1.1 网络

     大型计算机的连接数

1.2 变量名等价性

1.3 数学集合

 

2 实现

2.1 quick-find算法:

public class UF {
    private int[] id;
    private int count;
    public UF(int N) {
    count = N;
    id = new int[N];
    for(int i = 0;i<N;i++) {
        id[i] = i;
    }    
    }
    public int count() {
        return this.count;
    }
    public boolean connected(int q,int p) {
                return find(q)==find(p);
    }
    public int find(int q){

        //return id[q];
    }
    public void union(int q,int p) {
        // TO do
    

    }
} 

    算法实现经历了 从quick-find 到quick-union再到加权的quick-union的改进,这里给出最终的实现算法:

public class WeightQuickUnionUF {
    private int[] id;
    private int[] sz;
    private int count;
    public WeightQuickUnionUF(int N) {
        count=N;
        id = new int[N];
        for (int i=0;i<N ;i++) {
            id[i] = i;
        }
        sz= new int[N];
        for (int i=0;i<N;i++) {
            sz[i] = i;
        }

    }
    public int count() {

        return count;
    }
    public boolean connected(int q,int p) {
        return find(q) == find(p);
    }
    public int find(int q) {
        while(q != id[q]) {
            q = id[q];
        }
        return q;
    }
    public void union(int p,int q) {
        int i = find(p);
        int j = find(q);
        if (i==j) return;
        if (sz[i]<sz[j]) {id[i] = j;sz[j]+=sz[i];}
        else  {id[j]=i;sz[i]+=sz[j];} 
        count--;
    }



}

 

点赞