• 树状数组(Binary Indexed Tree)


    一、概述

      树状数组即Binary Indexed Tree或者Fenwick Tree,是一种用于高效处理数字的列表更新和求范围和的数据结构。它可以以O(logn)的时间得到前缀和num[1..i],并同时支持O(logn)时间内支持动态单点值的修改。

      树状数组解决的问题就是存在一个长度为n的数组nums,我们如何高效的执行以下操作:

    • update(ind,val) 将val的值加到数组的ind位置上
    • prefixSum(ind) 求数组前ind个位置上的数字和
    • rangeSum(from,to) 求数组[from..to]求数和

      当执行update的数量很少,prefixSum或者rangeSum的操作很多时,我们可以为原数组nums创建一个相同大小的数组sum,sum[i]表示前i个(包括第i个)的数字和。这样prefixSum(ind)=sum[ind],rangeSum(from,to) = sum[to]-sum[from]+nums[from].
    当update的操作频率增大时,每次update(ind,val)将对数组sum的i>=ind的所有位置进行修改。树状数组就是对这种情况的一种改进。

    二、建立BIT

      这里我们假设一段大小为15的数组[1,4,3,2,8,7,6,5,4,10,12,14,15,9,13,11],构建后的数组是怎么样的的,用下图表示:

      从图中可以看出BIT是用数组表示的并且构造BIT数组的方式是一种分层的方式,具体的做法是每一层的一段连续的位置,假设其中k表示该层某段连续位置的第一个数,则bit[k] = nums[k],当i在这段连续的位置时bit[i]=num[k]+num[k+1]+...+num[i],(i-k为2的指数次方,当i-k!=2的幂次方是bit[i]为空,将其放入下一层计算)。

      在正式建立树状数组之前我们介绍一下prefixSum(ind) 和 update(ind,val)这个操作

    2.1、prefixSum(ind)

      我们已经得到了BIT数组,怎么求原数组中前i个数的和,假设求sum[13]. 将13进行分层:13(1101B)=1+4+8 prefixSum(13) = bit[13]+bit[13-1]+bit[13-1-4],从图中可以证明这一点 bit[13] = nums[13] bit[12] = nums[9..12] bit[8] = [1..8];即:bit[1101B]+bit[1100B]+bit[1000B] (每次将二进制的最后一个1变为0将得到下一个bit的位置)。代码表示如下:
    public int prefixSum(int[] bit, int idx) {
        int sum = 0;
        for(int i=idx;i>=0;i-=i&(-i))
          sum+=bit[i];
        return sum;
      }
    

    其中i-=i&(-i)即为减去二进制形式最右边的1得到的值。

    2.2、 update

      ind是在原数组上要修改的位置,val表示在ind位置上增加的值(如果val是修改后的值,可以将其与原值相减得到增加的值)。假设我要在nums[5]的位置上增加val,那么bit相应改变的位置有bit[5],bit[6],bit[8]。5->101B,6->110B,8->1000B,观察BIT数组下标的二进制形式,每次都为在最右边为1的位置上加上1。

    update的代码如下:

    public void update(int[] bit,int idx,int val) {
        	for(int i=idx;i<bit.length;i+=i&(-i))
        		bit[i]+=val;
        }
    

    23、创建BIT数组

      创建BIT数组就是首先初始化一个与原数组nums相同大小的数组bit全为0,遍历nums当下标为i时执行操作update(bit,i,nums[i]);
    for(int i=1;i<nums.length;i++)
        update(bit,i,nums[i]);
    

    注意本文中所有数组的下标都是从1开始。

  • 相关阅读:
    C# Enum,Int,String的互相转换
    彻底弄懂css中单位px和em,rem的区别
    HTML特殊字符大全2
    网页特殊符号HTML代码大全
    HTML特殊字符大全
    收集一些特殊的符号
    jQuery 获取屏幕高度、宽度
    HTMLParser 使用详解
    C# 操作Word知识汇总
    C#编程总结(一)序列化
  • 原文地址:https://www.cnblogs.com/Mrfanl/p/11745435.html
Copyright © 2020-2023  润新知