樹狀數組(模板+原理)

原理出自 http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html


昨天學了一下樹狀數組,隨筆都寫了一大半,結果一個不小心就把他給刪了,哎。。。。。。今天就當是複習吧!再寫一次。

         如果給定一個數組,要你求裏面所有數的和,一般都會想到累加。但是當那個數組很大的時候,累加就顯得太耗時了,時間複雜度爲O(n),並且採用累加的方法還有一個侷限,那就是,當修改掉數組中的元素後,仍然要你求數組中某段元素的和,就顯得麻煩了。所以我們就要用到樹狀數組,他的時間複雜度爲O(lgn),相比之下就快得多。下面就講一下什麼是樹狀數組:

         一般講到樹狀數組都會少不了下面這個圖:

         

         下面來分析一下上面那個圖看能得出什麼規律:

         據圖可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。

         分析上面的幾組式子可知,當 i 爲奇數時,ci=ai ;當 i 爲偶數時,就要看 i 的因子中最多有二的多少次冪,例如,6 的因子中有 2 的一次冪,等於 2 ,所以 c6=a5+a6(由六向前數兩個數的和),4 的因子中有 2 的兩次冪,等於 4 ,所以 c4=a1+a2+a3+a4(由四向前數四個數的和)。

        (一)有公式:cn=a(n-a^k+1)+.........+an(其中 k 爲 n 的二進制表示中從右往左數的 0 的個數)。

         那麼,如何求 a^k 呢?求法如下:

int lowbit(int x)
{
     return x&(-x);   
}

         lowbit()的返回值就是 2^k 次方的值。

         求出來 2^k 之後,數組 c 的值就都出來了,接下來我們要求數組中所有元素的和。

         (二)求數組的和的算法如下:

         (1)首先,令sum=0,轉向第二步;

         (2)接下來判斷,如果 n>0 的話,就令sum=sum+cn轉向第三步,否則的話,終止算法,返回 sum 的值;

         (3)n=n - lowbit(n)(將n的二進制表示的最後一個零刪掉),回第二步。

          代碼實現:

int Sum(int n)
{
    int sum=0;
    while(n>0)
    {
         sum+=c[n];
         n=n-lowbit(n);
    }   
    return sum;
}

         (三)當數組中的元素有變更時,樹狀數組就發揮它的優勢了,算法如下(修改爲給某個節點 i 加上 x ):

         (1)當 i<=n 時,執行下一步;否則的話,算法結束;

         (2)ci=ci+x ,i=i+lowbit(i)(在 i 的二進制表示的最後加零),返回第一步。

          代碼實現:

void change(int i,int x)
{
     while(i<=n)
     {
          c[i]=c[i]+x;
          i=i+lowbit(i);
     }
}


發佈了141 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章