博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ACM知识---树状数组
阅读量:3945 次
发布时间:2019-05-24

本文共 1219 字,大约阅读时间需要 4 分钟。

树状数组是一种非常高效的数据结构,不过对于其的使用一般都会有比较明确的数据处理的特点吧,正常的数据处理分为取值和取区间值,如果我们用最为低效的方法:遍历,那么时间复杂度较高,而如果使用前缀和的方式也可以非常快的解决问题,但是前缀和使用的前提是不能修改数据为前提的,如果修改了数据,那么针对数组后面的数据也是需要修改的,那么时间复杂度就较高,而树状数组解决了这个问题,它的原理就是找一个规律用一维数组存储,但是不同于前缀和,前缀和的数组的一个数是与其下标前面所有的数都有关联的于是导致需要修改的数变大,而树状数组是找到一种规律,使得一维数组当中有关联的数据减少,所以修改一个数的时候,只需要修改树下面的子树的数据就可以了,所以修改的次数就是树的深度,最终时间复杂度也就是logn级别的。

存储方式:

我找到的博客当中,存储的方式都是与二进制有关,我介绍一下:

比如你要存一个下标为1的数:其二进制就是0001,1右边的0的个数为0,所以树状数组当中我们下标为1的个数为2的0次方的个元素的和。

如果下标为2,那么其二进制为0010,1右边的0的个数为1,那么下标为2的树状数组当中存储的是2的1次方的个元素的和。

如果下标为3,那么二进制为0011,后面就是一个元素的和。

注意:这里我们知道是几个元素的和之后,最后的元素一定是当前这个数组的坐标。

比如树状数组当中下标为3的,只需要存3下标的一个就可以了。

求元素个数的函数很简单:

 int lowbit(int x){

    return x&(-x);  
}

-x意思是x的二进制码取反再+1,如原来0001,取反后成为1110,再加1,就变成了1111,与后输出,就成了0001,很神奇对吧?这样你就发现他元素个数恰好就是上述的要求。

下面叙述求和操作:

int getsum(int x){

   int sum = 0;
    while(x > 0){
             sum+=A[x];       //A数组表示树状数组
            x-=lowbit(x);  }
    return sum; }

为什么要减去lowbit(x)的呢,因为lowbit表示了以x开始往左边几个下标元素,这里A【x】表示的是从x开始往左数lowbit(x)个值,那么x减去lowbit(x)就表示这几个元素已经加上了,继续循环就可以了。

更新数据操作:

void update(int x,int num){

      while(x <= n){               //n指的是树状数组当中元素个数,这里注意一点树状数组元素个数与原数组个数的元素个数相同
            A[x] +=num;        //num为修改值
            x +=lowbit(x);
 }
这里又为什么加lowbit(x)呢,我们找找规律就可以发现,因为A【x】其中x为最后一个元素,我们可以发现包含x下标的元素在之后出现就只有当x+lowbit(x)的时候包含x下标元素,也是我们需要修改的元素。

这就是树状数组了。

加油,臭咸鱼!!

转载地址:http://vomwi.baihongyu.com/

你可能感兴趣的文章
objdump的使用方法
查看>>
编译错误处理noproguard.classes-with-local.dex已杀死
查看>>
LTE - CSFB技术
查看>>
GSM链路层信令协议
查看>>
技术道德
查看>>
“需求为王”才是根本
查看>>
高效率的危害
查看>>
寻找边缘性创新
查看>>
让创意瞄准市场
查看>>
高效经理人应具有的八个重要习惯
查看>>
优秀的领导者能读懂人才
查看>>
大智若愚也是领导力
查看>>
android如何编译MTK的模拟器
查看>>
android如何添加AP中要使用的第三方JAR文件
查看>>
利用sudo命令为Ubuntu分配管理权限
查看>>
Ubuntu下几个重要apt-get命令用法与加速UBUNTU
查看>>
Ubuntu中网页各种插件安装命令
查看>>
使用tar命令备份Ubuntu系统
查看>>
ubuntu flash 文字乱码解决方案
查看>>
在ubuntu中运行exe文件
查看>>