概念
树状数组或者二叉索引树也称作Binary Indexed Tree,又叫做Fenwick树;它的查询和修改的时间复杂度都是log(n),空间复杂度则为O(n),这是因为树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描。通常使用在高效的计算数列的前缀和,区间和。
其中a数组就是原数组,c数组则是树状数组,可以发现
原理
lowbit
它通过公式来得出k,其中k就是该值从末尾开始0的个数。然后将其得出的结果加上x自身就可以得出当前节点的父亲节点的位置或者是x减去其结果就可以得出上一个父亲节点的位置。比如当前是6,二进制就是0110,k为2,那么6+2=8,而C(8)则是C(6)的父亲节点的位置;相反,6-2=4,则是C(6)的上一个父亲节点的位置。
计算机中负数是以补码的方式保存的,补码是源码取反+1得来的,大家可以试着将一个源码和它的补码做一下&运算,就知道为什么能得到最后一个1和它右边的子部位了。
更新
当我们要对最底层的值进行更新时,那么它相应的父亲节点存储的和也需要进行更新,所以修改的代码如下:
查询
而查询的时候,则需要向前进行统计
15=(1111)2,通过lowbit分解,它可以变成4个数的和:
(1111)2=(1)2+(10)2+(100)2+(1000)2,然后我们分析这个倒着跳的过程。
减去15的最小的2的幂次2^0得到14。
减去14的最小的2的幂次2^1得到12。
减去12的最小的2的幂次2^2得到8。
减去8的最小的2的幂次2^3得到0。
所以C(15) = C(14) + C(12) + C(8) + C(0),由图也可以得知,其结果是正确的。
除此之外,树状数组能够快速的求任意区间的和,设sum(k) = A[1] + A[2] + … + A[k],则A[i] + A[i+1] + … + A[j] = sum(j) - sum(i-1)。