樹狀數組

樹狀數組(Binary Indexed Tree(BIT), Fenwick Tree)是一個查詢和修改複雜度都爲log(n)的數據結構。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改一個元素的值;經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只能查詢其中一個元素的值。


假設數組a[1..n],那麼查詢a[1]+...+a[n]的時間是log級別的,而且是一個在線的數據結構,支持隨時修改某個元素的值,複雜度也爲log級別。
來觀察這個圖:

樹狀數組的結構圖
令這棵樹的結點編號爲C1,C2...Cn。令每個結點的值爲這棵樹的值的總和,那麼容易發現:
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
...
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
這裏有一個有趣的性質:
設節點編號爲x,那麼這個節點管轄的區間爲2^k(其中k爲x二進制末尾0的個數)個元素。因爲這個區間最後一個元素必然爲Ax,
所以很明顯:Cn = A(n – 2^k + 1) + ... + An


(1) 算這個2^k有一個快捷的辦法,定義一個函數如下即可:

int lowbit(int x){
    return x&(x^(x–1));
}
利用機器補碼特性,也可以寫成:

int lowbit(int x){
    return x&(-x);
}
求出來 2^k 之後,數組 c 的值就都出來了,接下來我們要求數組中所有元素的和。

(2) 當想要查詢一個SUM(n)(求a[n]的和),可以依據如下算法即可:
step1: 令sum = 0,轉第二步;
step2: 假如n <= 0,算法結束,返回sum值,否則sum = sum + Cn,轉第三步;
step3: 令n = n – lowbit(n),轉第二步。
可以看出,這個算法就是將這一個個區間的和全部加起來,爲什麼是效率是log(n)的呢?

證明:
n = n – lowbit(n)這一步,實際上等價於將n的二進制的最後一個1減去。而n的二進制裏最多有log(n)個1,所以查詢效率是log(n)的。

代碼實現:

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

(3) 修改一個節點,必須修改其所有祖先,最壞情況下爲修改第一個元素,最多有log(n)的祖先。

修改算法如下(給某個結點i加上x):

step1: 當 i<=n 時,執行下一步;否則的話,算法結束;
step2: ci=ci+x ,i=i+lowbit(i)(在 i 的二進制表示的最後加零),返回第一步。

注: i = i +lowbit(i)這個過程實際上也只是一個把末尾1補爲0的過程。

代碼實現:

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


(以下文字出自  吳豪文章《樹狀數組》:
世界上沒有免費的午餐,你喜歡上樹狀數組,你就一定要承受它的缺點,不過有一點我還沒有絕對地搞清楚,有人說樹狀數組可以解“最長不下降子序列”問題,但這個應該會涉及到求某一個區間範圍內最值。但是貌似樹狀數組要符合減法原則,也就是說不能求某一個區間範圍內最值。初步來講,我認爲“樹狀數組解最長不下降子序列”和“減法原則”可能並不矛盾,可能有一種符合“減法原則”解法,我不做深入討論探究了。 
下面引用一段話: 
在很多的情況下,線段樹都可以用樹狀數組實現.凡是能用樹狀數組的一定能用線段樹。當題目不滿足減法原則的時候,就只能用線段樹,不能用樹狀數組.例如數列操作如果讓我們求出一段數字中最大或者最小的數字,就不能用樹狀數組了。 
除了上面的“減法原則”之外,還需要說明的是:樹狀數組由 1 開始。 習慣用 C/C++的同志們申請地址的時候必須從 0 開始,自然而然地,我們習慣了第一個元素是 0,但是樹狀數組必須由 1 開始。具體細節想一下就會知道,那是因爲跟那個“將 k 化爲二進制數時末尾 0 的個數”有關。 


參考資料:

1. http://baike.baidu.com/view/1420784.htm?fr=aladdin

2. http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html

3. http://dongxicheng.org/structure/binary_indexed_tree/


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