對樹狀陣列的 簡單 理解

2021-08-16 15:04:39 字數 1500 閱讀 9989

當時學資料結構的時候,暑假訓練的課上得雲裡霧裡,自己還忙於補之前的題,導致只聽完了課,內容都沒有消化. 學完了樹狀陣列,只知道怎麼用,該用的時候還想不起來用...現在細想一下, 簡單的樹狀陣列就是 點修改、區間查詢,能降一位o(n)到log(n).

現在有乙個序列,a[n],假設n=16. 設

c[1]=a[1]    c[2]=a[1]+a[2]

c[3]=a[3]    c[4]=a[1]+a[2]+a[3]+a[4]

c[5]=a[5]    c[6]=a[5]+a[6]

c[7]=a[7]   c[8]=a[1]+.....+a[8]

1.lowbit()

通過觀察,我們發現每乙個c[i]的節點表示的和中最後一項都是c[i],他們所包含的項的個數是i的二進位制最後一位1所代表的數(或者是說2^k,k為末尾零的個數),這也是lowbit() 函式要做的事情

int lowbit(int i)
其實想要求這個lowbit的話,我們最先想到的是,對於乙個數x的二進位制,如果我們減去1,那麼從末尾開始,所有末尾的0都會變成1,最後乙個1也會變成0,只有這部分會變化;所以我們用 x去異或(x-1),就會把我們用得到的位保留下來並置為1,之前沒有關係的位都置為0,這一串1再和x進行與運算,就把原來是0的位去掉了,原來是1的位還是1,就得到了我們要求的lowbit的值。

int lowbit(int i)
i&-i是利用了負數補碼的性質,取反加1,進製只影響到最後一位1,非常巧妙,以前一直在照寫,卻沒有明白為什麼,實在是慚愧。

那麼,所有的c[i]節點構成了一棵樹,這個數就是樹狀陣列。

2.get()

int get(int i) 

return ans;

}

查詢操作是查詢區間和,將節點加到一塊。比如我查詢的是sum(5),5的二進位制是101,從最後乙個1開始取節點c[5];減去lowbit變成100,取c[4];減去lowbit變成0,停止;加和即為a[1]+...+a[5],即sum(5).

為什麼是o(log(n))呢,因為查詢時是二進位制數中每有乙個1就進行一次操作,做多有log(n)個1。

3.set()

void set(int i, int x) 

}

修改包含當前要修改的位置的節點即可。i每次加lowbit是將包含這個節點的值都進行一次修改,包含乙個a[i]節點的c[i]節點最多有log(n)+1個。拿16和1舉例,顯而易見,1,2,4,8,16都包含1。複雜度還是o(log(n))級別

樹狀陣列還能轉變為區間修改點查詢。

4.個人理解

覺得樹狀陣列之所以能降低到o(log(n))的複雜度是因為,樹狀陣列用類似二分的辦法將陣列儲存下來。16分為左8整體,左8又被拆出來左4,以此類推......  還有就是,利用二進位制,或者說是2的次方的性質。 log也是以2為底的~  降複雜度有時候就跟二分或者二進位制(的胡搞...)有關。稍微高階一點的應用過幾天在學2333

樹狀陣列理解

無意間看到樹狀陣列,查了很多資料被各種圖和公式繞暈了,下面記錄一點個人理解。假設陣列a 0 a 1 a 2 a n 記0 m元素之和為sum m 0 當我們頻繁的求s m 時,第一種方法不適用,當我們頻繁的修改陣列a時,第二種方法每次都要修改陣列s,修改陣列s的時間複雜度為o n 而樹狀陣列可以很好...

樹狀陣列理解

c i 代表 子樹的葉子結點的權值之和 如圖可以知道 c 1 a 1 c 2 a 1 a 2 c 3 a 3 c 4 a 1 a 2 a 3 a 4 c 5 a 5 c 6 a 5 a 6 c 7 a 7 c 8 a 1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 再將其轉化為二進位製看...

簡單的樹狀陣列

目錄對結構的探索 引 zkw 線段樹介紹 對結構的探索 續 小結future 當然我不可能把所有知識 羅列,希望我的文字會給你帶來一些啟發和消遣。單單拿出樹狀陣列來說的話,可以說它是乙個利用某些數列資訊的區間可並性,平衡數列單點修改和字首查詢時間複雜度的資料結構,乙個樹狀陣列維護乙個數列的資訊。樹狀...