树状数组入门(快速求和问题)

树状数组 解决求和问题

树状数组是一种数据结构主要解决快速求和的问题,其次他还可以快速的查找最大值,但是查找最大值还是推荐使用线段树来做,相比之下树状数组更节省空间。
有时候觉得树状数组难以理解,我觉得根本原因是:你还在用十进制的视角来看待树状数组,下面的讲解我会时刻提醒你转换到二进制的视角。
lowbit()函数:顾名思义,lowbit这个函数的功能就是求某一个数的二进制表示中最低的一位1,举个例子,x = 6,它的二进制为110,那么lowbit(x)就返回2,因为最后一位1表示2。
那么怎么求lowbit呢?
还记得 剑指Offer66题之每日6题 - 第二天中的第五题中讲过的如何消掉最后一位1吗?我们就是先消掉最后一位1,然后再用原数减去消掉最后一位1后的数,答案就是lowbit(x)的结果;
第二种方法就是计算机组成原理课上老师教过我们求负数的补码的简便方法:把这个数的二进制写出来,然后从右向左找到第一个1(这个1就是我们要求的结果,但是现在表示不出来,后来的操作就是让这个1能表示出来),这个1不要动和这个1右边的二进制不变,左边的二进制依次取反,这样就求出的一个数的补码,说这个方法主要是让我们理解一个负数的补码在二进制上的特征,然后我们把这个负数对应的正数与该负数与运算一下,由于这个1的左边的二进制与正数的原码对应的部分是相反的,所以相与一定都为0,;由于这个1和这个1右边的二进制都是不变的,因此,相与后还是原来的样子,故,这样搞出来的结果就是lowbit(x)的结果。
下面有张图能看出更好的表示
这里写图片描述

基本操作并不难,记住模板后直接使用就好
下面是我随手写的代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
#define MAXIN 9999999
using namespace std;

int a[MAXIN];
int n;

int lowbit(int x){
    return x&(-x);
}
//lowbie函数与计算机工作原理有关,计算机进行补码运算
//二进制的且运算能够将x的二进制的最后一位为1的权值返回
//例如:lowbit(4),12 = 1100;返回值应该是4;

//增加
void add(int x,int v){
    while(x<=n){
        a[x]+=v;
        x+=lowbit(x);
    }
}

//查出前缀和
int seekSum(int v){
    int sum=0;
    while(v){
        sum+=a[v];
        v-=lowbit(v);
    }
    return sum;
}

int main()
{
    //树状数组没有初始结构所以开始使用的时候都要初始化后使用
    //树状数组不能够直接将value更改,只能是增加或是减少
    n=100;//树状数组结构的大小

    //初始化
    memset(a,0,n);

    //创建树状数组
    for(int i=1;i<=n;i++){
        add(i,i);
    }

    //查看前缀和
    printf("%d\n",seekSum(5));
    printf("%d\n",seekSum(12));
    return 0;
}

希望能够帮助到你!!

猜你喜欢

转载自blog.csdn.net/weixin_40488730/article/details/81302801