树状数组

来源:互联网 发布:js 数组 json 编辑:程序博客网 时间:2024/04/30 02:26

树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值。


假设数组a[1..n],那么查询a[1]+...+a[n]的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。
来观察这个图:

树状数组的结构图
令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
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


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

int lowbit(int x){    return x&(x^(x–1));}
利用机器补码特性,也可以写成:

int lowbit(int x){    return x&(-x);}
求出来 2^k 之后,数组 c 的值就都出来了,接下来我们要求数组中所有元素的和。

(2) 当想要查询一个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)的。

代码实现:

int Sum(int n){    int sum = 0;    while(n>0){        sum += C[n];        n -= lowbit(n);    }    return sum;}

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

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

step1: 当 i<=n 时,执行下一步;否则的话,算法结束;
step2: ci=ci+x ,i=i+lowbit(i)(在 i 的二进制表示的最后加零),返回第一步。

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

代码实现:

void change(int i, int x){    while(i<=n){        C[i] += x;        i += lowbit(i);    }}


(以下文字出自  吴豪文章《树状数组》:)
世界上没有免费的午餐,你喜欢上树状数组,你就一定要承受它的缺点,不过有一点我还没有绝对地搞清楚,有人说树状数组可以解“最长不下降子序列”问题,但这个应该会涉及到求某一个区间范围内最值。但是貌似树状数组要符合减法原则,也就是说不能求某一个区间范围内最值。初步来讲,我认为“树状数组解最长不下降子序列”和“减法原则”可能并不矛盾,可能有一种符合“减法原则”解法,我不做深入讨论探究了。 
下面引用一段话: 
在很多的情况下,线段树都可以用树状数组实现.凡是能用树状数组的一定能用线段树。当题目不满足减法原则的时候,就只能用线段树,不能用树状数组.例如数列操作如果让我们求出一段数字中最大或者最小的数字,就不能用树状数组了。 
除了上面的“减法原则”之外,还需要说明的是:树状数组由 1 开始。 习惯用 C/C++的同志们申请地址的时候必须从 0 开始,自然而然地,我们习惯了第一个元素是 0,但是树状数组必须由 1 开始。具体细节想一下就会知道,那是因为跟那个“将 k 化为二进制数时末尾 0 的个数”有关。 


参考资料:

1. http://baike.baidu.com/view/1420784.htm?fr=aladdin

2. http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html

3. http://dongxicheng.org/structure/binary_indexed_tree/


0 0
原创粉丝点击