【数据结构】Binary Indexed Tree

二叉索引树 <树状数组>

假设我们有N个盒子,该数据结构就可以使我们快速的进行以下两个操作:

1.第i个盒子的增改                          <更改点数据>

2.第k个到第i个盒子数据的累加和    <区间求值>

时间复杂度均为 O(logn)

核心思想:二分法

其主要由三个函数构成:

int lowbit(int x){return x&-x;}
/*与数据索引相关联*/
int sum(int x)
{
    int amount=0;
    while(x>0)
    {
        amount += tree[x];
        x -= lowbit(x);
    }
    return amount;
}
/*计算 1 - X 段的和*/
void updata(int x,int val)
{
    while(x<=n)
    {
        tree[x] += val;
        x += lowbit(x);
    }
}
/*增改数据*/

     

         首先我们把目光放在第一个函数lowbit,我们都知道计算机里面,整数都是使用补码 来表示,假设X为7的话 ,那么它的二进制就是0111,而-X就是其取反加1的结果,也就是1001那将他们相与的结果就是0001,这就是该函数的结果。而它的作用将会在下两个函数中起到画龙点睛的作用。


        现在,我们知道了lowbit函数所能够带来的结果,但它的真正意义是什么呢?笔者也百思不得其解,但研究上图,以及联系代码来看,其主要是起  联系和简化的作用(本人拙见,望诸君指点)


           让我们通过这样一组数据来继续进行了解。明白两个概念

概念1.对于每一个结点 i ,如果它是左子节点其父节点为 i+lowbit ,若为右,则为 i - lowbit.

概念2.每一个tree[]数组的值都对应      一段连续和.

看上图的虚线和深色点,将其相连是不是一颗 二叉树 。tree[]数组里包含的就是 结点的数据

再结合概念2也就不难明白tree[]的值了。

举个栗子了解updata函数,如果我们对 第3结点 进行 +1 操作,我们发现,这并不只是单单加一这么简单,对其进行操作对后面的tree[]数组的值也有影响,所以,也要将与之关联的进行同样的+1操作。


        (操作后 影响的结果)

sum函数值的计算同样是基于这一点,我们仍然用7来举栗子

7的二进制是0111 根据代码先累加7结点的数据,再回溯累加6的,再回溯累加4的,结束,返回值。

可能有读者会问,为什么要回溯6,4?

7(0111) 的lowbit 为1 减之为6

6(0110) 的lowbit 为2 减之为4

4(0100) 的lowbit 为4 减之为0   结束

这样,在普通数组需要7次操作的运算,通过这种方法只需要3次就足够了,可以说是极大的优化

从宏观角度来说就是将其代表的线段和累加,而这也是基于二分之上所做的。

参考文献:<算法竞赛入门经典>

                   TOPCODER

猜你喜欢

转载自blog.csdn.net/qq_41220023/article/details/80472044