数组树/fenwicktree/Binary Indexed Tree

在解类似 leetcode 307题区域和检索 - 数组可修改的题时,我们可以使用一种比较小众的数据结构,数组树。

数组树的结构依托于数组,它的结构看起来类似下面这种:
在这里插入图片描述
1,2,3。。。。代表他们在数组中的位置,在了解为什么有这种数据结构之前,请务必先看看上面提到的leetcode 307题。

在数组树中有两个主要的操作函数更新查询。在更新数组中的某一个位置的数值的时候,其所有祖先节点全部都要更新,比如节点1更新,则2,4,8节点全部都要更新,更新的方式为当前节点的值加上子节点或自身更新后增加的值,比如现在节点1的值变为1,相对于原来的0值增加了1,则1,2,4,8的值都变为1;节点2的值变为4,相对于原来的0值增加了4,则2,4,8的值变为5。这种更新方式实际上是要在数组树中维护这样一个关系,节点值为sum(child.val) + self.val。

如果要更新数组树,那么必须找到更新的节点的所有祖先节点,计算方法为 i += lowbit(i);lowbit()的意思为数的二进制从最低位往高位计算,到第一个为1的位置,这之间的所有的二进制构成的数,比如1(b0001)的lowbit为(b0001),相加为2(b0010),2的lowbit为(b0010)相加为4(b0100)。lowbit的计算公式为lowbit(x) = x & (-x);以5为例,x = 5 = b0110 ,-x = ~x + 1 = b1010,lowbit(5) = 0010;

以上就是就是数组树的更新过程,如果要查询数组树,也就是获得前i个数组元素的和为多少时,毕竟这才是我们的目的,这时就需要用到另一种计算节点的方式。经过上面数组树更新方式的描述,我们可以很清楚的知道4存放了1,2,3,4的和,6存放了5,6的和,8存放了所有值的和,如果要计算前7个数的和,可想而知是要将数组树中4,6,7节点值相加。这实际上也有一个计算公式,i -= lowbit(i);它看起来就像下面这样。
在这里插入图片描述
这就是leetcode 307题所需要的数据结构,现在我们使用这个数据结构将这一题解决。在做题过程中一定要注意fenwicktree的下标是从1开始的。并且更新过程中传入的是相对于原来该元素增加的值。

class NumArray {
    FenwickTree tree;
    int[] nums;

    public NumArray(int[] nums) {
        tree =  new FenwickTree(nums.length + 1);
        this.nums = nums;
        for(int i = 0; i < nums.length; i++){
            tree.update(i + 1, nums[i]);
        }
    }
    
    public void update(int i, int val) {
        tree.update(i + 1, val - nums[i]);
        nums[i] = val;
    }
    
    public int sumRange(int i, int j) {
        return tree.query(j + 1) - tree.query(i);
    }
}

class FenwickTree{
    int[] sums;

    public FenwickTree(int n){
        sums = new int[n];
    }

    public void update(int i, int delta){
        while(i < sums.length){
            sums[i] += delta;
            i += lowbit(i);
        }
    }

    public int query(int i){
        int sum = 0;
        while(i > 0){
            sum += sums[i];
            i -= lowbit(i);
        }
        return sum;
    }

    private int lowbit(int i){
        return i&-i;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值