二叉索引树 树状数组

Posted FuTaimeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉索引树 树状数组相关的知识,希望对你有一定的参考价值。

树状数组 维护一个序列 a1 a2 a3……an

支持两种操作:

1. sum(int a,int b) a~b的区间和

2. add(int x,int d) 第x个数增加d

 

设lowbit(x)为x的二进制最右边的1表示的值

如lowbit(38288)=lowbit(1001010110010000)=10000=16

 

对于节点i,如果它是左子结点,父节点为i+lowbit(i);如果它是右子节点,那么父节点是i-lowbit(i)

 

定义一个数组C 

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

...

C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16

这里有一个有趣的性质:

设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,

所以很明显:Cn = A(n – 2^k + 1) + ... + An

算这个2^k有一个快捷的办法,定义一个函数如下即可:

intlowbit(intx){

returnx&(x^(x–1));

}

利用机器补码特性,也可以写成:

intlowbit(intx){

returnx&(-x);

}

当想要查询一个SUM(n)(求a[n]的和),可以依据如下算法即可:

step1: 令sum = 0,转第二步;

step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;

step3: 令n = n – lowbit(n),转第二步。

可以看出,这个算法就是将这一个个区间的和全部加起来,为什么是效率是log(n)的呢?以下给出证明:

n = n – lowbit(n)这一步实际上等价于将n的二进制的最后一个1减去。而n的二进制里最多有log(n)个1,所以查询效率是log(n)的。

那么修改呢,修改一个节点,必须修改其所有祖先,最坏情况下为修改第一个元素,最多有log(n)的祖先。

所以修改算法如下(给某个结点i加上x):

step1: 当i > n时,算法结束,否则转第二步;

step2: Ci = Ci + x, i = i + lowbit(i)转第一步。

i = i +lowbit(i)这个过程实际上也只是一个把末尾1补为0的过程。

对于数组求和来说树状数组简直太快了!

注:

求lowbit(x)的建议公式:

lowbit(x):=x and (x xor (x - 1));

或lowbit(x):=x and (-x);

lowbit(x)即为2^k的值。

 

以上是关于二叉索引树 树状数组的主要内容,如果未能解决你的问题,请参考以下文章

二叉索引树 树状数组

浅析树状数组(二叉索引树)及一些模板

二叉索引树

深入理解二叉索引树:从LeetCode实践出发(题号307315327493)

深入理解二叉索引树:从LeetCode实践出发(题号307315327493)

树状数组的基操