前端也要學點資料結構 神奇的樹狀陣列

2021-09-08 11:19:55 字數 2700 閱讀 2434

最近在學習位運算,正好把樹狀陣列總結下,也算是能正式給data structure建個分類。

那麼,樹狀陣列到底有什麼用呢?誠然,一樣沒什麼卵用的東西我們學它幹嘛。

下面舉個樹狀陣列的經典應用:區間求和。

假設我們有如下陣列(陣列元素從index=1開始):

var a = [x, 1, 2, 3, 4, 5, 6, 7, 8, 9];
我們設定兩種操作,modify(index, x)表示將a[index]元素加上x,query(n, m)表示求解a[n] ~ a[m]之間元素的和。如果不了解樹狀陣列(當然假設更不了解線段樹等其他資料結構),你可能會很容易地寫下如下**:

var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

function query(n, m)

function modify(index, x)

ok,複雜度為o(1)的刪改和複雜度為o(n)的查詢。如果資料量很大,這樣反覆的查詢是相當耗時的。我們退一步想,如果只有query(n, m)這個操作,很容易想到用sum陣列預處理前n項的和,然後用sum[m] - sum[n-1]獲得答案。但是如果要修改a[index]的值,因為該項影響所有index之後的sum陣列元素,所以如果這樣做複雜度變為o(1)的查詢和o(n)的刪改,並沒有什麼卵用。

但是這個思路是美好的,我們可以用乙個sum陣列儲存一段特定的區間段的值。假設我們有a[1] ~ a[9]9個元素,我們根據乙個特定的規則:

sum[1] = a[1];

sum[2] = a[1] + a[2];

sum[3] = a[3];

sum[4] = a[1] + a[2] + a[3] + a[4];

sum[5] = a[5];

sum[6] = a[5] + a[6];

sum[7] = a[7];

sum[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8];

sum[9] = a[9];

如果要求a[1] ~ a[9]的和,即為sum[9] + sum[8],如果要求a[1] ~ a[7]的和,即為sum[7] + sum[6] + sum[4],如果要改變a[1]的值,改變sum陣列中和a[1]有關的項即可(即sum[1]sum[2]sum[4]sum[8])。 這就是樹狀陣列!實現了o(logn)的查詢和刪改。但是如何將a陣列和sum陣列聯絡起來?

來觀察這個圖:

令這棵樹的結點編號為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

這裡有乙個有趣的性質:設節點編號為x,那麼這個節點管轄的區間為2^k(其中k為x二進位制末尾0的個數)個元素。因為這個區間最後乙個元素必然為ax,所以很明顯:cn = a(n – 2^k + 1) + ... + an,算這個2^k有乙個快捷的辦法,定義乙個函式如下即可(求解2^k即求二進位製碼右邊第一位1的值):

int lowbit(int x)
當想要查詢乙個sum(n)(求a[1]~a[n]的和),可以依據如下演算法即可:

令sum = 0,轉第二步;

假如n <= 0,演算法結束,返回sum值,否則sum = sum + cn,轉第三步;

令n = n – lowbit(n),轉第二步。

可以看出,這個演算法就是將這乙個個區間的和全部加起來。

那麼修改呢,修改乙個節點,必須修改其所有祖先,最壞情況下為修改第乙個元素,最多有log(n)的祖先。所以修改演算法如下(給某個結點i加上x):

當i > n時,演算法結束,否則轉第二步;

ci = ci + x, i = i + lowbit(i)轉第一步。i = i + lowbit(i)這個過程實際上也只是乙個把末尾1補為0的過程。 對於陣列求和來說樹狀陣列簡直太快了!

關於這部分的**,將在下文樹狀陣列的具體三大應用中給出。

關於樹狀陣列,有一點需要注意,為了方便,樹狀陣列的a陣列基本都是從index=1開始的。

下文中樓主會分析下樹狀陣列的三大應用場景:改點求段,改段求點,改段求段

前端也要學點資料結構 神奇的樹狀陣列的三大應用

前文我們 了樹狀陣列的原理。樹狀陣列就是一種資料結構,它天生用來維護陣列的字首和,從而可以快速求得某乙個區間的和,並支援對元素的值進行修改。但是樹狀陣列並非只有這一種功能,變形後它還能衍生出兩個功能,本文我們就來分別討論下樹狀陣列這三大功能。永遠要記住,基本的樹狀陣列維護的是陣列的字首和,所有的區間...

資料結構 樹狀陣列的幾種用法

單點修改 區間修改 單點查詢 區間查詢 洛谷p3374 洛谷p3368 洛谷p3374 includeusing namespace std intn,m int tree 2000010 int lowbit int k void add int x,intk int sum int x retu...

資料庫中樹狀資料結構的設計

img img 乙個cms頻道分類設計,大體意思是通過自定義id的方式。id 步長 2位 那麼一級分類為 01 99 varchar 20 2 10 那麼id 01 99999999999999999999 如果你覺得分類不夠用的可以加大步長,級次關係 img quote select schann...