树状数组(快速求数组的前n项和)

lowbit.js

/**
lowbit(x)是x的二进制表达式中最低位的1所对应的值。
x=x(n)x(n-1)x(n-2)...x(m)...x2x1共n位
假设x(m)位为1,小于m的位全为0。那么其反码为
y(n)y(n-1)...y(m)...y2y1,y(k)和x(k)互补
则y(m)为0,小于m的位全为1。所以其补码为
y(n)y(n-1)...1...00   y(m)变成了1,小于m位的全变成了0。
比如,6的二进制是110,所以lowbit(6)=2。
 */
function lowbit(i){
    return i&-i;
}
function test(){
    let lbs = [];
    for(let i=0;i<20;i++){
        console.info(i+'->'+lowbit(i));
    }
}
test();
module.exports = lowbit;

blocktree.js

/**
 * 树状数组
 * 快速求数组的前n项和。
 * 树状数组的设计,s[i]设计为第i项(包括第i项)之前lowbit项的和。注意从第0项开始,但是第0项特殊处理。
 * 比如
 * s[1]=a[1],第
 * s[2]=a[2]+a[1]
 * s[3]=a[3]
 * ...
 * http://www.cnblogs.com/huangxincheng/archive/2012/12/05/2802858.html
 * 这个地址上的代码不全,而且数组下标不是从0开始,而且没有初始化s的代码。所以我对其进行了补充和修改。
 * */
const lowbit = require('./lowbit');
function createTreeArray(array){
    let arr = array;
    let s = [];
    if(arr.length>0){
        s.push(arr[0]);
    }
    for(let i=1;i<arr.length;i++){
        let lb = lowbit(i);
        s[i] = arr.slice(i-lb+1,i+1).reduce((prev,curr)=>prev+curr,0);
    }
    /*s.forEach((item,i)=>{
        console.info(`s[${i}]=${item}`);
    });*/
    return {
        updatedArray(i,newValue){
            let diff = newValue - arr[i];
            for(let j=i;j<arr.length;j+=lowbit(j)){
                s[j] = s[j]+diff;
            }
        },
        sum(i){
            let res = s[0];
            while(i>0){
                res+=s[i];
                i -= lowbit(i);
            }
            return res;
        },
        s
    };
}
function test(){
    let arr = [3,4,8,2,3,1,7];
    arr = [5,6];
    let bt = createTreeArray(arr);
    for(let i=0;i<bt.s.length;i++){
        console.info(`sum[${i}]=${bt.sum(i)}`);
    }
    bt.updatedArray(3,7);
    console.info('after update ...');
    for(let i=0;i<bt.s.length;i++){
        console.info(`sum[${i}]=${bt.sum(i)}`);
    }
}
test();
module.exports = createTreeArray;

猜你喜欢

转载自blog.csdn.net/zhoujiaping123/article/details/80327417