先说必要性
假设程序中有一个数组,需要求他的前n项和这时需要累加,如果数字很大时可以计算时间复杂度为O(n)。
而且累加的方式是一次性的,如果需要对数据进行更改,那么你需要重新计算所有的数的和。又要进行一次时间复杂度为O(n)的计算。如果有n个数据进行修改,时间复杂度将变为O(n^2)。对此我们引入树状数组。
上图
先找规律
c1 = a1;
c2 = a1 + a2;
c3 = a3;
c4 = a1 + a2 + a3 + a4;
c5 = a5;
………………
c16 = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16;
首先
当i为奇数的时候 ci = ai;
当i为偶数的时候 ci 所包含的个数相当于 本身因子中2的级数的最大次;
上一句话的人话版就是 i转化成二进制从后往前数 有几个零就包含几个a的项;
上公式: cn = (n - a ^ k + 1) + ………………………… + an;
其中a^k的求法为:
int lowbit (int a)
{
return a & (-a);
}
lowbit函数返回值就是 a ^ k;
用树状数组重新解决开头的问题
累加
1.令sum = 0;
2.sum += cn;
3.n -= lowbit(n);返回第2步;
以上3步为累加上代码;
int sum (int c[], int n)
{
int sum = 0;
while(n > 0)
{
sum += c[n];
n -= lowbit(n);
}
}
数组的某个元素发生变更时
1.当i < n 时 执行2.
2.ci += x, i += lowbit(i) ;返回第一步
int change (int i, int x) // i表示更改的位置, x表示改为的数。
{
while(i <= n)
{
c[i] += x;
i += lowbit(i);
}
}
计算一下时间复杂度