树状数组
树状数组
定义
树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。
作用:
- 实现求数组前缀和
- 实现批量更新
- 区间和快速查询(实质是两个端点前缀和相减得到)
下图为树状数组实现原理,红色箭头代表更新操作的执行顺序,绿色箭头代表查找操作的顺序
lowbit(x)
就是求x
最后一个1所代表的值,例如lowbit(9) = lowbit(1001) = 1
,
机器计算表达式为lowbit(x) = x & (-x)
,以12也就是1100
为例:
计算机组成原理:
正数的原、反、补码都是其本身,负数的反码等于原码取反, 补码等于反码+1,计算都是通过补码进行
x = 0 1100 (12)
原、反、补码都是01100,最前面的0为符号位
-x = 1 1100 (-12)
原码 1 1100
反码 1 0011
补码 1 0100
x & ( - x ) = 01100 & 10100 = 00100
即取到了最后一位的值 100
let arr = [];
function lowbit(x) {
return x & (-x);
}
/* 给index索引的结点+value */
function add(index, value) {
while (index <= 16) {
arr[index] = arr[index] == undefined ? value : (arr[index] + value);
index += lowbit(index);
}
}
/* 查询前缀和 */
function query(index) {/* 查询前缀和,结束位置为index */
let sum = 0;
while (index > 0) {
sum += arr[index] == undefined ? 0 : arr[index];
console.log(index, arr[index])
index -= lowbit(index);
}
return sum;
}
/* 查询x~y区间 */
function getSum(x, y) {
return query(y) - query(x - 1);
}