qiukeqi

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

简述

树状数组的更新和查询区间值的和的时间复杂度都是 O(logN), 在频繁查询数组区间值的场景中可以适用.
正常数组的更新时间复杂度是 O(1), 查询区间值的和的时间复杂度为 O(N).
前缀数组的更新时间复杂度是 O(N), 查询区间值的和的时间复杂度为 O(1).

数组 更新时间复杂度 求区间元素和时间复杂度
树状数组 O(logN) O(logN)
平常数组 O(1) O(N)
前缀数组 O(N) O(1)

分析可看Renference中的链接

c++14环境 代码

#include <vector>
#include <iostream>
#include <math.h>
using namespace std;
/**
简易的树状数组 改变值和查询区间值的时间复杂度为  O(logN) 空间复杂度为 O(1) 
接口:
TreeArray(int n=0) 实例化内容大小为n的树状数组 
int size() 容器的实际大小 
int query(int r)  返回 [0,r] 之间的元素的和 
int query(int l, int r) 返回 [l,r] 之间元素的和
void update(int i, int x) 将下标为 i 的元素的值更新为 x (TreeArray[i] = x) 
void change(int i, int x) 将下表为 i 的元素的值改变 x (TreeArray[i] += x) 
**/
class TreeArray{
public:
	TreeArray(int n = 0){
		buffer.resize(n+1,0);
	}
	int size(){
		return buffer.size()-1;
	}
	
	//查询区间 [0,r] 内元素的和 
	int query(int r){
		if(r < 0 || r >= size()){
			cout<<"ERROR: INVALID QUEY PARAMETER r="<<r<<" IN TreeArray::query(int i)"<<endl; 
			throw 0;
		}
		int ans = 0;
		for(int pos = r+1; pos; pos -= lowbit(pos)){
			ans += buffer[pos];
		}
		return ans;
	}
	
	//查询区间 [l,r] 之间元素的和  
	int query(int l, int  r){
		if(l < 0 || l >= size() || r < 0 || r >= size() || r < l){
			cout<<"ERROR: INVALID QUEY PARAMETER l="<<l<<"  r="<<r<<" IN TreeArray::query(int l, int r)"<<endl; 
			throw 0;
		}
		
		return l == 0 ? query(r) : query(r) - query(l-1);
	}
	
	//将下标为 i 的元素的值更新为 x (TreeArray[i] = x) 
	void update(int i, int x){
		if(i < 0 || i >= size()){
			cout<<"ERROR: INVALID UPDATE PARAMETER i="<<i<<" IN TreeArray::update(int i, int x)"<<endl; 
			throw 0;
		}

		x = i == 0 ? x - buffer[1] : x - (query(i) - query(i-1));	
		change(i,x);
	}
	
	//将下表为 i 的元素的值改变 x (TreeArray[i] += x) 
	void change(int i, int x){
		if(i < 0 || i >= size()){
			cout<<"ERROR: INVALID UPDATE PARAMETER i="<<i<<" IN TreeArray::change(int i, int x)"<<endl; 
			throw 0;
		}
		int bufferSize = buffer.size();
		
		for(int pos = i+1; pos < bufferSize; pos += lowbit(pos)){
			buffer[pos] += x;
		}
	}
private:
	int lowbit(int i){
		return i & (-i);
	}
	
	vector<int> buffer;
}; 

#include <stdio.h>
using namespace std;
int main()
{
	TreeArray temp(100);
	for(int i = 0; i < temp.size(); i++){
		temp.update(i,i);
	}
	cout<<temp.query(99)<<endl;
	cout<<temp.query(10)<<endl;
	cout<<temp.query(1,11)<<endl;
	cout<<temp.query(1,12)<<endl;
	return 0;
}

程序输出为:

4950 // 0 - 99 的和 
55  // 0 - 10 的和
66  // 1 - 11 的和
78  // 1 - 12 的和

Reference

知乎:Pecco 算法学习笔记(2) 获取时间2022/8/9

posted on 2022-08-09 14:55  qiukeqi  阅读(9)  评论(0)    收藏  举报