树状数组(Binary Indexed Tree)是一种可以同时快速得到数组的前缀和和快速更新数组的数据结构。
树状数组有两个操作:
1 void update(int i, int delta):更新数组中下标为i的元素的值,将其值加delta
2 int prefixSum(int i):计算数组到下标为i的元素的前缀和
通常对于求长度为n的数组的前缀和的任务,我们可以将数组的前缀和提前计算出来保存到一个新的数组,此时求前缀和只有O(1)的时间复杂度,但是此时对数组中元素进行更新操作有O(n)的时间复杂度,如果数组元素需要频繁更新,则这种方法就会很慢。而使用树状数组这种数据结构可以使得计算前缀和与更新数组元素这两个操作的时间复杂度都为O(log n)。
时间复杂度:更新和求前缀和操作都是
空间复杂度:
线段树与树状数组非常相似,都是在长度为n的数组中,以O(log n)的时间复杂度更新数组元素,以O(log n)的时间复杂度得到区间和/前缀和。
java代码实现:
/**
* index prefixSum
* (1) 1 1
* (2) 10 2
* (3) 11 3+2
* (4) 100 4
* (5) 101 5+4
* (6) 110 6+4
* (7) 111 7+6+4
* (8) 1000 8
* (9) 1001 9+8
* (10)1010 10+8
* (11)1011 11+10+8
* (12)1100 12+8
* (13)1101 13+12+8
* (14)1110 14+12+8
* (15)1111 15+14+12+8
*/
public class BinaryIndexedTree {
private int[] a;
private int[] tree;
public BinaryIndexedTree(int size) {
a = new int[size];
tree = new int[size + 1];
}
public BinaryIndexedTree(int[] a) {
this.a = a;
tree = new int[a.length + 1];
System.arraycopy(a, 0, tree, 1, a.length);
for (int i = 1; i < tree.length; i++) {
int j = i + (i & -i);
if (j < tree.length) {
tree[j] += tree[i];
}
}
}
public void update(int i, int delta) {
a[i++] += delta;
while (i < tree.length) {
tree[i] += delta;
i = i + (i & -i);
}
}
public int prefixSum(int i) {
i += 1;
int sum = 0;
while (i > 0) {
sum += tree[i];
i = i - (i & -i);
}
return sum;
}
}