树状数组篇:
首先我们来了解一个应用:
我们需要求一个数组的前N项的和:
这么简单的问题我们不是可以这样吗?
for( int i=0;i<N;i++)
{
sum+=array[i];
}
cout<<sum;
但是当我们需要控制时间复杂读小于O(n),则我们需要怎么办呢?
这个时候我们就可以利用树状数组了:
树状数组的修改和控制的时间复杂度都是O(logn)
下面介绍什么是树状数组
C数组就是树状数组 A数组是原数组 C[i]是对应A数组的树状数组 当我们需要的时候就直接按照下表搜索
我们建立一个这样的数组的时间复杂度时O(nlogn)
由上图可知
C[1]=A[1]
C[2]=A[1]+A[2]
C[3]=A[3]
C[4]=A[1+A[2]+A[3]+A[4]
C[5]=A[5]
C[6]=A[5]+A[6]
C[7]=A[7]
C[8]=A[1]+ A[2]+A[3]+ A[4]+ A[5]+ A[6]+ A[7]+ A[8]
…
不难发现:
SUM(i)就是数组A的前i项的和
比如i=2
假如计算机的位数是16位的则i的二进制是:
0000000000000010
-i的二进制是
1111111111111110
则i&(-i)=2
0000000000000010
1111111111111110
= 0000000000000010=2
具体的去了解计算机的原码、补码、反码的转换方式现在就是上面的具体代码怎么实现:
在Add函数中最重要便是:
如果A[i]在C中的某些项中则这些项需要加上A[i],因此每一个A[i]中的项都需要进行
一项相同的操作:就是把这个A[i]加到含有它的C数组中间去
所以就有:
#这里使用的是Python语言 如果没有学过就当成伪代码看即可
def Lowbit(x):
return x&(-x)
def Add(x,A,C):
y=x
while x < len(L)-1:
A[x] += C[y]
x+=Lowbit(x)
在C数组做好了那么如何求前N项和呢?
我们要利用这条性质:
所以就有:
def Get_Sum(x,C)
sum=0
while x > 0:
sum += C[x]
x -= Lowbit(x)
return sum
整个完整的代码如下
# This is tree array python source code
import numpy as np
def Lowbit(x):
return x&(-x)
def Add(x,P,L):
y=x
while x < len(L)-1:
P[x] += L[y]
x+=Lowbit(x)
def Build_Tree_Array(L,P):
for x in range(1,len(L)):
Add(x,P,L)
def Get_Sum(x,L):
sum=0
while x > 0:
sum += L[x]
x -= Lowbit(x)
return sum
if __name__=='__main__':#代码从这里开始执行
L=np.zeros(11,int)#L是原始的A数组一个一维数组含由11个数
P=np.zeros(11,int)#P是C数组初始化都为0
Build_Tree_Array(L,P)
y=1
for x in input().split():#这里是输入1 2 3 4 5 6 7 8 9 10这里是给A即L数组赋初值
L[y]=x
y+=1
Build_Tree_Array(L,P)构建数
print (Get_Sum(4,P))#求前4项的和
#Input:1 2 3 4 5 6 7 8 9 10
# Output:10
上面就是树状数组的内容了 这个数据结构曾经在CCF考试中出现过还是比较重要的 也是ACM的必修课