union-find算法分析(2)

2.3.weighted-quick-union——加權quick-union算法

上篇的quick-union算法的效率之因此低(平方級別),最主要的緣由是union(p,q)方法,隨意將一棵樹鏈接到另外一棵樹上(一棵樹對應一個連通份量)。算法

1.若是是小樹(高度低)鏈接到大樹的根節點(高度高),則小樹的高度加1,而整個樹的高度不變。數組

2.若是是大樹(高度高)鏈接到小樹的根節點(高度低),則大樹的高度加1,而整個樹的高度由原來的小樹高度變成大樹高度加1。app

p_w_picpath

根據quick-union算法分析,find(p)訪問的數組的次數與節點p所在的高度有關。高度越高,訪問數組的次數越多。ide

因而可知,爲了減小訪問數組的次數,提升算法效率,在執行union(p,q)操做時,確保是狀況1,即小樹鏈接到大樹上。爲此,須要一個數組sz[]來記錄觸點p所在的連通份量含有的觸點(觸點越多,對應的樹的節點越多,即爲大樹)。測試

3.固然還有一種特殊狀況,即p和q所在的連通份量對應的樹高度相等,此時不管是p鏈接到q仍是q鏈接到p,樹的高度都會增長。在加權quick-union算法中,這是最壞的狀況。ui

所以,由加權quick-union構成的樹的高度將遠小於未加權所構造的樹的高度。spa

   1: public class WeightedQuickUnionUF extends QuickUnionUF {
   2:  
   3:     /**
   4:      * sz[p]表示觸點p所在的連通份量所含的觸點數
   5:      */
   6:     private int[] sz;
   7:  
   8:     public WeightedQuickUnionUF(int N) {
   9:         super(N);
  10:         // TODO Auto-generated constructor stub
  11:         sz = new int[N];
  12:         for (int i = 0; i < N; i++)
  13:             sz[i] = 1;// 初始化時,每一個觸點都是一個連通份量
  14:     }
  15:  
  16:  
  17:     @Override
  18:     public void union(int p, int q) {
  19:         // TODO Auto-generated method stub
  20:         int pRoot = find(p);
  21:         int qRoot = find(q);
  22:         
  23:         if(pRoot == qRoot)
  24:             return;
  25:         
  26:         if(sz[pRoot] < sz[qRoot]){//當觸點p所在的連通份量對應的樹是小樹,則鏈接到q的連通份量上去
  27:             id[pRoot] = qRoot;
  28:             sz[qRoot] += sz[pRoot];//不要忘了,被鏈接的樹包含的節點數要相應的增長
  29:         }else{//當觸點p所在的連通份量對應的樹是大樹,則q所在的連通份量鏈接到p的連通份量上去
  30:             id[qRoot] = pRoot;
  31:             sz[pRoot] += sz[qRoot];
  32:         }
  33:         
  34:         count -- ;
  35:     }
  36:     
  37:     public static void main(String[] args) {
  38:         DirectInput.directInput(args);
  39:         int N = StdIn.readInt();
  40:         UF uf = new WeightedQuickUnionUF(N);
  41:         for(int i=0;i<N;i++){
  42:             int p = StdIn.readInt();
  43:             int q = StdIn.readInt();
  44:             
  45:             if(uf.connected(p, q)) continue;
  46:             
  47:             uf.union(p, q);
  48:             StdOut.println(p + " " + q);
  49:         }
  50:         StdOut.println(uf.count() + " components");
  51:     }
  52:  
  53: }

 

測試結果code

p_w_picpath

算法分析component

1.最壞的狀況:將要被歸併的樹的大小老是相等的(且老是2^n)。每一個樹均是含有2^n節點的滿二叉樹,所以高度正好是n。當歸並兩個含有2^n節點的樹時,獲得含有2^(n+1)個節點的書,由此樹的高度增長到n+1。由此可知,加權quick-union算法是對數級別的。即對於N個觸點所構成的樹最高的高度爲lgN。blog

2.狀況1的最壞的狀況是怎麼得來的?

簡單的分析可知,加權quick-union算法不可能會獲得線性表(未加權的quick-union會產生退化成線性表的樹)。所以,每層的節點越多,樹的高度就越小。最壞的狀況就是滿二叉樹。

3.加權quick-union算法處理N個觸點,M條鏈接時最多訪問數組cMlgN次。(c爲常數。每處理一條鏈接,調用一次union(p,q)方法。而union(p,q)是lgN級別的。lg[height(p)] + lg[height(q)] + 5 = clgN,M次即爲cMlgN)。而quick-find算法以及某些狀況下未加權的quick-union算法至少訪問數組MN次。

 p_w_picpath

相關文章
相關標籤/搜索