樹狀陣列, 又名二叉索引樹(binary indexed tree), 利用該結構能夠有效地解決區間和查詢問題, 並且查詢的時間複雜度是o(log n)
字首和查詢
如圖所示, 在原始陣列的基礎上我們引入乙個輔助陣列c, c[i]代表的含義是陣列i的值以及所有遞迴的前驅之和,整個輔助陣列看上去像一顆樹, 因此得名. 舉例
從上面的計算看出, 本來13個值的和, 這裡通過輔助陣列只有3個數相加, 這也就是他能夠o(log n)查詢字首和的秘密, 所有之前的資料按照倍增的思想,只要達到2的次方的規模即接管和值, c[2], c[4], c[8]均是乙個數便計算出和值
現在的問題是如何根據index找出前驅呢
咋一看,還真看不出什麼特點, 我們嘗試一下把所有的數值用二進位制表示一下
從上面的可以看出, 當前節點到前驅節點是當前節點減去只有最末尾為1的數, 知道0為止, 至於怎麼求最末尾為1的數,請參考巧用位運算
def lowbit(self, i): # return i & (~i + 1) # 因為(~i + 1)是負數的表示方法, 所以可以簡化成下面的寫法 return i & (-i)
字首和的查詢**如下
# 字首和查詢, i是陣列的index def query(self, i): result = self.c[i] pre = (i+1) - self.lowbit(i+1) while pre > 0: result += self.c[pre-1] pre = pre - self.lowbit(pre) return result
區間和查詢(i, j)
樹狀陣列的建立(時間複雜度n*o(log n))
# 根據陣列建立樹狀陣列, 自動處理下標, 沒有下標從1開始的要求 def build(self): for i, val in enumerate(self.arr): left = (i+1) - self.lowbit(i+1) self.c[i] = self.arr[i] pre = i while pre > left: self.c[i] += self.c[pre-1] pre = pre - self.lowbit(pre)
原始陣列數值更新(只能單點更新)
有利有弊, 加快區間和查詢的情況下, 其實是增加了更新時的負擔, 所以樹狀陣列適用於區間查詢頻繁, 而鮮有更新的場景
**如下
# 單點更新, i是index, value是需要更新的值 def update(self, i, value): # 算出差值,方便後繼更新 diff = value - self.arr[i] if diff != 0: self.arr[i] += diff self.c[i] += diff next = (i+1) + self.lowbit(i+1) while next <= len(self.arr)+1: self.c[next-1] += diff next = next + self.lowbit(next)
喜歡本篇內容, 下方贊、在看或分享吧!? C 樹狀陣列模板
前言 昨日學習了一波樹狀陣列,學習好了演算法步驟和原理後,自己寫了c 的板子,大家可複製貼上使用即可。樹狀陣列 是一種用於高效處理對乙個儲存數字的列表進行更新及求字首和的資料結構。關於樹狀陣列的演算法步驟 樹狀陣列 binary indexed tree 看這一篇就夠了,大家看這篇就好了。樹狀陣列模...
C 樹狀陣列介紹
使用陣列來模擬樹形結構 大部分基於區間上的更新和求和問題 修改和查詢的複雜度為o logn 比線段樹係數少得多,比傳統陣列要快,而且容易編寫。我們使用a陣列表示原來的陣列,c陣列表示我們的樹狀陣列 可以表示為 c i a i 2k 1 a i 2k 2 a i k為i的二進位制中從最低位到高位連續零...
樹狀陣列1 樹狀陣列入門
仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...