树状数组

时间复杂度

树状数组是一个查询和修改的时间复杂度都为 l o g ( n ) log(n) log(n)的数据结构。一般来说树状数组能解的题目,线段树都能解,但是线段树能解的问题,树状数组不一定能解。但是树状数组的有点在于方便实现,代码量少。

树状数组的结构

树状数组_第1张图片

图中的A数组是原来的数组,C数组就是树状数组,如果先将A数组的每个元素都先放在C数组中,则:
C数组中每一位所存的信息都由前面的某些位的信息构成,以求A的前缀和为例
C 1 C_1 C1中存放的和就是 C 1 C_1 C1
C 2 C_2 C2中存放的和是 C 1 + C 2 C_1+C_2 C1+C2
C 3 C_3 C3中存放的和就是 C 3 C_3 C3
C 4 C_4 C4中存放的和就是 C 2 + C 3 + C 4 C_2+C_3+C_4 C2+C3+C4

如何去寻找树状数组中每一位所对应的其他位

假设当前位是i,现在要将i位置的和加到i后面的某些位上。
树状数组每个位置的下标其实是以二进制来对应的,例如:

1d=1b
2d=10b=1b+1b
3d=11b
4d=100b=11b+1b=10b+10b

即将i写成2进制,并从右往左找,找到第一个1,并用i加上这个1所对应的的权值,就是i后面的第一个要找的位。
那么如何高效的寻找上述的1成为这个数据结构的关键。
对任意的一个数i(二进制是xxxx1...),它的相反数-i(二进制是XXXX1...
上面表达式二进制中的xxxx取反是XXXX...表示不定数量的0
那么求从右往左的第一个1所对应的的权值那就是 i & ( − i ) i\&(-i) i&(i),一般用lowbit(i)表示这个值

如何构建和更新树状数组

对树状数组而言,构建和更新其实是一样的操作:

  • 先将A数组中的每一个数都放在C数组的 1 1 1~ N N N
  • 然后对C数组中的每一个元素将其下标i不断地加上lowbit(i),直到大于 N N N为止,这样一个树状数组就构建完成

如何查询前缀和

查询A数组中下标为i的前缀和

  • 先定义一个sum存放和
  • sum不断地累加 C i C_i Ci,且每次累加后令 i − = l o w b i t ( i ) i-=lowbit(i) i=lowbit(i),直到i<1为止

练手题:如何用树状数组求数组中的中位数

你可能感兴趣的:(数据结构)