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

相关文章
相关标签/搜索