最近在學習位運算,正好把樹狀陣列總結下,也算是能正式給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...