BIT数据结构

应用场景

定义数组array[n],求数组array[i]到array[j]的和(部分和)。在这种情况下,用一个简单的遍历可以解决问题,复杂度为O(n)。如果这种操作执行了m次,那么复杂度为O(mn),而树状数组可以把复杂度降至O(m*logn),适用于更新少但是部分和操作次数多的场景。

树状数组

树状数组(Binary Indexed Tree),本质就是一种通过二进制位来维护一个序列前i个和的数据结构,所以在其实更应该直白地翻译为二进制索引树。树状数组的索引都是以1开始,首先看一个例子。
设原始数组为a[8] = {3,4,5,6,7,8,9,2},那么树状数组e可以通过如下方式得到:
e[1] = a[1]
e[2] = a[1]+a[2]
e[3] = a[3]
e[4] = a[1]+a[2]+a[3]+a[4]=e[1]+e[2]+e[3]
e[5] = a[5]
e[6] = a[5]+a[6]
e[7] = a[7]
e[8] = a[1]+a[2]+...+a[8]
解释如下:

  1. 每一个树状数组元素都是一个或者多个原始数组的和。
  2. 如何确定当前树状数组是几个原始数组元素的和?
    将数组下标i表示为二进制,i从末尾开始连续0的个数定义为k。那么
e[i]=a[i-2^k +1]+a[i-2^k+2]+...+a[i]。

例如:e[8(1000)] = a[1]+a[2]+...+a[8]

后缀前缀

为了方便构造和使用树状数组,定义前缀和后缀两个操作。后缀一般在初始化和更新BIT数组中使用,前缀是为了求和的时候跳过重复的元素。

后缀

i的后缀为最为靠近i,且二进制末尾连续0的个数比i多的坐标。如e[2(10)]的后缀为e[4(100)],e[4(100)]的后缀为e[8(1000)]。后缀主要用来构造和更新树状数组
后缀的计算公式为:

//lowBit(i) = -i&i 或者 (i-1^i)&i 
//e[i]的后缀为e[i+low(i)]
int lowBit(int i){
  return -i&i;
}
构造树状数组

可以通过一次完整的扫描即可构造出树状数组,扫描的过程中每次去更新当前值的后缀即可。

 private void establishBIT() {
        for (int i = 1; i < orgin.length; i++) {
            if(i + lowBit(i)

如果其中某一项发生改变,只需要更新一下与之相关的后缀的值。

//更新操作
//结构内部以下标1作为数组的开始位
public void update(int pos, int num){
        if(pos<0||pos>orgin.length-1)
            return;
        int temp = orgin[pos+1];
        orgin[pos+1] = num;
        int delta = num-temp;
        pos = pos+1;
        while(pos

前缀

前缀的计算公式为:

//lowBit(i) = -i&i 或者 (i-1^i)&i 
//e[i] 的前缀为e[i-lowBit(i)]

前缀一般在求和的过程中会用到。

 public int sum(int p){
        int res= 0;
        while(p>0){
            res+=bit[p];
            p = p-lowBit(p);
        }
        return res;
    }

后缀是为了不重复计算元素,因为在BIT数组中每一项都是原始数组的一个或者多个的和。

源码

public class BIT {
    private int[] orgin;
    private int[] bit;

    public BIT(int[] inArray){
        orgin = new int[inArray.length+1];
        bit = new int[inArray.length+1];
        for(int i=1;iorgin.length-1)
            return;
        int temp = orgin[pos+1];
        orgin[pos+1] = num;
        int delta = num-temp;
        pos = pos+1;
        while(pos0){
            res+=bit[p];
            p = p-lowBit(p);
        }
        return res;
    }
    public static void main(String[] args) {
        int[] input = new int[]{1,2,4,5,2,6,8,9};
        BIT bit = new BIT(input);
        System.out.println(bit.showBIT());
        System.out.println(bit.sum(1));
        bit.update(0,4);
        System.out.println(bit.showBIT());
    }
}

参考资料

https://www.cnblogs.com/grandyang/p/6657956.html
https://blog.csdn.net/u011567017/article/details/52252852
https://www.byvoid.com/zhs/blog/binary-index-tree

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