基本思想:
树状数组是用来解决在数组元素动态变化的情况下,高效的计算子数组和的一种数据结构,其更新效率和计算和的效率均为O(logn),和普通的sum数组不同的是,虽然sum数组计算子数组和的效率为O(1),但是在面对数组元素动态变化的情况下,其更新效率为O(n)。Fenwick数组的更新方式如下图:
首先需要一个辅助函数lowbit,用于计算最低位所在的位置,比如二进制110,那么它返回的是二进制10,这个函数利用补码的特性x&(-x)即可实现。有了这个函数,就可以实现数组的更新与查询。我们需要两个数组vec和tree,vec用于存储原始数据,tree是树状数组。对于更新操作,记录下该位置和原始数据之差diff,然后i += lowbit(i)进行更新。对于i到j之间的子数组之和,计算0到j和0到i两部分的和相减即可,而对于0到i之和,从第i个数开始i -= lowbit(i),并将tree[i]相加即可。代码如下,即Leetcode 307答案
1 class NumArray { 2 public: 3 NumArray(vector<int> nums) { 4 vec = vector<int>(nums.size(),0); 5 tree = vector<int>(nums.size()+1); 6 for(int i = 0;i != nums.size();++i){ 7 update(i,nums[i]); 8 vec[i] = nums[i]; 9 } 10 } 11 12 void update(int i, int val) { 13 int diff = val-vec[i]; 14 vec[i] = val; 15 int index = i+1; 16 while(index < tree.size()){ 17 tree[index] += diff; 18 index += lowBit(index); 19 } 20 } 21 22 int sumRange(int i, int j) { 23 return getSum(j+1)-getSum(i); 24 } 25 private: 26 vector<int> tree; 27 vector<int> vec; 28 int lowBit(int x){ 29 return x&(-x); 30 } 31 int getSum(int x){ 32 int result = 0; 33 while(x > 0){ 34 result += tree[x]; 35 x -= lowBit(x); 36 } 37 return result; 38 } 39 };
参考资料:
https://www.youtube.com/watch?v=WbafSgetDDk&t=748s