前言
今天我们继续学习维护区间的数据结构与算法;
在之前的学习中,我们学习了前缀和与差分,实现了如何维护区间和,以及区间查询,修改
在前缀和与差分两中数据结构上,我们知道对于维护区间和的查询只需要O(1)
但是对于单点或者区间修改的时间复杂度却是O(n)
我们试图寻找一种结构,他对于两种维护的时间复杂度都尽可能少
---树状数组
树状数组
什么是树状数组?
树状数组(BIT Binary Index Tree)所以树状数组的实质是二进制下标树,对于它的实现与二进制无法分割
为什么会与二进制扯上关系? 在前言中我们提到,我们尝试寻找一种结构使得他在维护一个数列是,无论是在 修改 还是 维护区间和 等的操作上,都尽可能地简便,缩短时间。
根据学习过的知识,我们很容易想到对于维护一个数列,我们可以另开数组去维护原数列,并将原数列分成一个个区间,单点修改时,只更新包含这一元素的区间;求前n项和时,通过将区间进行组合,得到从1到n的区间,然后对所有用到的区间求和
树状数组就是这样一种数据结构,它巧妙的利用二进制去划分区间,其维护的时间复杂度为O(logN)怎么实现,原理是什么我们娓娓道来
树状数组的原理和实现
根据 任意正整数关于2的不重复次幂的唯一分解性质
我们知道 若一个正整数 x 的二进制可以表示为 Ak-1 Ak-2 … A2 A1 A0
其中等于1的位是ai1ai2ai3…
所以
x
可以被分解成
x
=
2
i
1
+
2
i
2
+
.
.
.
+
x
i
m
所以 x 可以被分解成\\ x=2^{i1} + 2^{i2} +...+x^{im}\\
所以x可以被分解成x=2i1+2i2+...+xim
不妨设 i1> i2 > i3 > … > im
那么区间【1,x】可以被分成O(logx)个小区间
这些小区间的共同特点是:若结尾为R,则区间长度就等于R的“二进制分解”下最小的2的次幂
即 lowbit(R)
例如
x
=
7
=
2
2
+
2
1
+
2
0
区间
[
1
,
7
]
可以分成
[
1
,
4
]
、
[
5
,
6
]
、
[
7
,
7
]
三个小区间
长度分别为
l
o
w
b
i
t
(
4
)
=
4
,
l
o
w
b
i
t
(
6
)
=
2
,
l
o
w
b
i
t
(
7
)
=
1
x=7 =2^2+2^1+2^0\\ 区间[ 1,7]可以分成[1,4]、[5,6]、[7,7]三个小区间\\ 长度分别为lowbit(4)=4, lowbit(6)=2, lowbit(7)=1
x=7=22+21+20区间[1,7]可以分成[1,4]、[5,6]、[7,7]三个小区间长度分别为lowbit(4)=4,lowbit(6)=2,lowbit(7)=1
什么是lowbit ?
lowbit(x) 即 取出非负整数 x 在二进制表示下最低位的 1 以及它后边 0 构成的数值
比如上面的 4 = 100 ,6 = 110 所以其最低为1与0组成的数分别为100与10
所以lowbit(4)= 4 ,lowbit(6)= 2
如何实现lowbit ?
l
o
w
b
i
t
(
x
)
=
(
x
)
&
(
−
x
)
lowbit(x)= (x) \And (-x)
lowbit(x)=(x)&(−x)
为什么可以这样?
我们需要知道,计算机里有符号数一般是以补码的形式存储的。
-x相当于x按位取反再加1,会把结尾处原来1000…的形式,变成0111…,再变成1000…;
而前面每一位都与原来相反。
这时我们再把它和x按位与,得到的结果便是lowbit(x)。
下面的图中举了两个例子:
知道了原理,接下来就是实现树状数组
我们会在(2)中展示树状数组的具体实现