【数据结构】树状数组 包含最简单的lowbit理解

树状数组,顾名思义,树的形状的数组,最终的数据结构还是一个数组

作用

树状数组的作用主要是用于对区间的查询,比如区间和,区间更新。

那么有人可能会问,求区间为什么不用前缀和,那不是更简单吗?

  • 求和
    在求和的时候前缀和跟树状数组是一样的甚至比树状数组更方便
  • 更新
    但是如果我们要更新这个数组呢,对于前缀和是不是平均复杂度是O(N)?树状数组在这个时候,可以做到O(logN),这一点树状数组有很大优势

所以我们最主要的就是,树状数组是怎么让一个数组可以做到求区间和跟更新都做到O(logN)复杂度的。

基本思想 - 二进制

首先,我们要知道,树状数组能有这么好的效果,最基本的思想是根据二进制来实现的,具体怎么实现的,接下来详讲。

1.将前缀和改成管理区间

对于更新数组最重要的一个问题就是对于前缀和,每个元素代表的数是从自身开始到前面所有的元素和,这样虽然方便了求区间结果,但是在根本上,将更新变成了O(N)的复杂度

所以树状数组的第一步就是,怎么改变前缀和,但是又能让他起到前缀和的作用呢?我们来看看他是怎么做的。

将前缀和改成管理区间到了这里就要介绍树状数组的关键函数lowbit了,这个函数将贯穿树状数组操作的始终,非常重要

1.1lowbit函数

lowbit(x)得到的是:从低位到高位数,第一个数字1的位置得到的二进制数

比如8=1000,lowbit(8) = 8 2=10 , lowbit(2) = 2, 5 = 110 lowbit(6) = 2

既然这一步是树状数组中最常用的一步,那么树状数组的性能就跟这一步息息相关,所以lowbit的实现非常简单

lowbit(x) = x & (-x)

所以说,大道至简啊,看上去非常简单的一个函数表达式,但是能完美解决我们的问题。

其实这个方法是用到了计算机底层计算用到的是补码的机制。


原码求补码有一个小技巧,那就是除去符号位,从右往左第一个1的下一位开始,所有位直接取反,这个不知道的可以去好好复习一下补码

从右往左第一位,看到这个是不是突然发现有点意思了。一个是原码,一个是补码,如果两个数&一下的话,补码跟原码有相同位的,是不是只有从右往左的第一个1?那么求与的话就肯定能得到我们想要的答案了


根据这个我们就能得到1-8的lowbit分别为

1 2 1 4 1 2 1 8

1.2管理区间

了解玩lowbit函数,那么回到我们根本的问题上,怎么将前缀和优化,达到相同的效果,但是更新的时候又不用O(N)的复杂度呢?

树状数组的做法是:

第i个位置管理[i - lowbit(i) + 1, i]区间,其实这里就可以换成区间或者其他我们想要的结果

只要顺着数字往下画竖线,碰到的第一根横线所覆盖的范围就是它能管理的范围。
在这里插入图片描述
每个数的前缀和改成了管理区间了,那么改成这个管理区间怎么优化更新呢?

比如我们需要将x的位置值+k,在前缀和里面我们是不是需要将所有排在x后面的数都+k,在树状数组就只需要找到能够管理到x的位置,+k就好了,这样一来,需要更新的复杂度就变成O(N)了

并且找到管理x位置的下标,只需要y = x + lowbit(x),然后迭代更新管理y位置的下标, z = y + lowbit(y)直到超过数组边界就好了 。

怎么理解这个管理区间i - lowbit(i) + 1, i]和查找管理i的下标i + lowbit(i)


我们用八位举例,对于00101000

我们先看i - lowbit(i) + 1 = 00100001,这就意味着,0010 0001-0010 1000都归 0010 1000管

对于0010 0100他的直系管理者 i + lowbit(i) = 0010 1000

但是对于0010 0010,他的直系管理者其实是i + lowbit(i) = 0010 0100,间接管理者才是0010 1000


综上,将前缀和改成管理区间后,更新x只要更新x的管理者就可以了,而管理者的数量是logX数量级的,X为数组长度len - x下标

2.求区间和

聊完更新,我们不能忘乐树状数组的本心,其实是为了求区间结果,管理区间只是为了让树状数组可以持续的接受更新,然后求更新后的区间。

我们前面知道,对于区间和而言,数组的每个元素的数值其实是他管理区间的所有元素和,

所以对于任意的[1,R]区间和,我们其实可以通过迭代求出结果

首先我们求出R和他的管理区间的和也就是位置R的数值,然后对于R - lowbit®也就是第一个R没有管理到的位置,求他的管理区间和,然后迭代求第一个没管理到的位置区间和,由此直到1,得到最终结果。

这样区间和的复杂度也就是O(logN)

所以求[L,R]的区间和,就是[1,L-1]和[1,R]区间和的差值

感谢您能看到末尾!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值