2021-04-11

树状数组

是什么

树状数组,又叫二叉索引树(BIT,Binary Indexed Tree),以其发明者命名为Fenwick树。其初衷是解决数据压缩里累计频率的计算问题,现多用于高效计算数列的前缀和,区间和。

累计频率

索引+分治

要求前缀和:只需要考虑前找规律即可。

img

取最后一个1:

1

单点更新

向右边找:

2 3

总结

  1. 树状数组用于求解给定数组中任意区间的累计频率(前缀和,区间和),支持单点更新,不支持增加和删除元素。

  2. 树状数组的本质也是一个数组,根据元素额索引建立里“逻辑上的”树形结构,元素之间便有了练习,所以也叫二叉索引树。

  3. 一般情况:

    1. 初始化:遍历所有元素:O(n) 更新到BIT中O(logn) 总计O(nlogn);
    2. 查询O(logn);
    3. 单点更新O(logn);

线段树

为什么线性数组求前缀和效率差

8

递归(后序遍历)实现查询和更新

建树

6
    //递归建树:后序遍历
    static void buildTree(int[] arr,int[] tree,int node,int start,int end){
        if(start==end){
            tree[node]=arr[start];
            return;
        }
        int left_node=2*node+1;
        int right_node=2*node+2;
        int mid=(start+end)/2;
        buildTree(arr, tree, left_node, start, mid);
        buildTree(arr, tree, right_node, mid+1, end);
        tree[node]=tree[left_node]+tree[right_node];

    }

更新

9
 //递归查找:后序遍历  执行更新
    static void update(int[] arr,int[] tree,int node,int start,int end,int idx,int val){
        if(start==end){
            arr[idx]=val;
            tree[node]=val;
            return;
        }
        int left_node=2*node+1;
        int right_node=2*node+2;
        int mid=(start+end)/2;
        if(idx>=start&&idx<=mid){
            update(arr, tree, left_node, start, mid, idx, val);
        }
        else
            update(arr, tree, right_node, mid+1, end, idx, val);

        tree[node]=tree[left_node]+tree[right_node];
   

    }

求区间和

9
    static int query(int[] arr,int[] tree,int node,int start,int end,int L,int R){
        System.out.println("start="+start);
        System.out.println("start="+end);
        System.out.println();
        if(L>end||R<start){
            return 0;
        }
        if(L<=start&&end<=R){
            return tree[node];
        }
        if(start==end){
            return tree[node];
        }
        int left_node=2*node+1;
        int right_node=2*node+2;
        int mid=(start+end)/2;
        int sum_left=query(arr, tree, left_node, start, mid, L, R);
        int sum_right=query(arr, tree, right_node, mid+1, end, L, R);
        return sum_left+sum_right;
        
    }

测试

    public static void main(String[] args) {
        int[] arr={1,3,5,7,9,11};
        int size=6;
        int[] tree=new int[MAX_LEN];
        //0号节点,表示区间和[0,5]
        buildTree(arr, tree, 0, 0, size-1);
        // for (int i = 0; i < 15; i++) {
        //     System.out.println("tree["+i+"]="+tree[i]);
        // }
        System.out.println();
        update(arr, tree, 0, 0, size-1,4,6);
        for (int i = 0; i < 15; i++) {
            System.out.println("tree["+i+"]="+tree[i]);
        }
        System.out.println();
        System.out.println(query(arr, tree, 0, 0, size-1,2,4));  
           
 
    }

总结

树状数组:数学

线段树:树递归

树状数组,线段树大法好!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值