树状数组

树状数组是一种非常巧妙的数据结构。对于一个普通数组,可以构造出一个对应的树状数组。普通数组中的元素存放的只是本身的信息,但树状数组中的元素存放的却是多个原数组的信息。

对于一个非负整数x,我们可以将它表示为二进制,设它的二进制形式中,结尾的0的个数为k。

对于树状数组,它的x位置上的元素表示的是原数组从x位置开始,往后数2^k个元素的信息(一般是它们的和,也可以是最大值或最小值)。

比如:

x=1时2^k=1,即它只包含本身的信息。其他奇数也一样。

x=2时2^k=2,即它包含2和1位置上的元素信息

x=4时2^k=4,即它包含4、3、2、1位置上的元素信息

x=6时2^k=2,即它包含6和5位置上的元素信息

……

对于x计算出它对应的2^k的方法非常简单,只要通过下面的函数:

int lowbit(int x)

{

return x & (-x);

}

这是一个非常巧妙的函数,对于树状数组的某个位置x而言,x + lowbit(x)表示它的上一级的结点,即包含它的信息的结点,而x - lowbit(x)表示比它小的不被它包含的最大结点。

比如当x=2时,lowbit(x)=2,则x+lowbit(x)=4,表示它的上一级结点是4,因为4包含了4、3、2、1的信息。

当x=7时,lowbit(x)=1,则x-lowbit(x)=6,表示比它小的不被它包含的最大结点是6。


树状数组的主要操作:

1、在某个位置的结点处增加一个值:在改变了原数组中元素的值之后,需要逐步向上修改上一级结点的信息。

2、统计第一个元素到当前元素的和:设置一个表示和的树状数组,然后使用上面的lowbit函数不断查找下一个不被包含的点,把所有的和加起来即可。

3、统计区间和:使用操作2中的方法,用较大的区间减去较小的区间就得到所求区间和了。


//BinaryIndexedTree.h

#ifndef _BINARY_INDEXED_TREE_
#define _BINARY_INDEXED_TREE_

#include <iostream>
#include <vector>
using namespace std;

class BinaryIndexedTree
{
public:
	BinaryIndexedTree(int _size);
	~BinaryIndexedTree();
	void addValue(int _pos, int _val);	//向数组的某个位置的元素增加某个值
	int getSum(int _beg, int _end);		//计算某个区间的元素的和
	int lowbit(int _val);				//计算某个数的二进制表示中,末尾有多少个0
protected:
private:
	int size;							//数组大小
	vector<int> number;					//原始数组
	vector<int> sum;					//树状数组
};

#endif

//BinaryIndexedTree.cpp

#include "BinaryIndexedTree.h"
using namespace std;

BinaryIndexedTree::BinaryIndexedTree(int _size): size(_size)
{
	number.resize(_size + 1);
	sum.resize(_size + 1);
	for (int i = 1; i <= size; ++i)
	{
		sum[i] = 0;
	}
	int num = 0;
	cout << "input elements:" << endl;
	for (int i = 1; i <= size; ++i)
	{
		cout << i << ": ";
		cin >> num;
		addValue(i, num);
	}
}

BinaryIndexedTree::~BinaryIndexedTree()
{
	number.clear();
	sum.clear();
}

int BinaryIndexedTree::lowbit(int _pos)
{
	return _pos & (-_pos);
}

void BinaryIndexedTree::addValue(int _pos, int _val)
{
	while (_pos <= size)
	{
		sum[_pos] += _val;
		_pos += lowbit(_pos);
	}
}

int BinaryIndexedTree::getSum(int _beg, int _end)
{
	if (_beg > _end)
	{
		int t = _beg;
		_beg = _end;
		_end = t;
	}
	if (_beg <= 0 || _end > size) return INT_MIN;
	int sumbeg = 0;
	int sumend = 0;
	_beg -= 1;
	while (_beg > 0)
	{
		sumbeg += sum[_beg];
		_beg -= lowbit(_beg);
	}
	while (_end > 0)
	{
		sumend += sum[_end];
		_end -= lowbit(_end);
	}
	return sumend - sumbeg;
}

//main.cpp

#include "BinaryIndexedTree.h"
#include <string>
using namespace std;

int main()
{
	int beg, end;
	int val, pos;
	int size;
	string str;
	cout << "input the size: ";
	cin >> size;
	BinaryIndexedTree tree(size);
	while (cin >> str)
	{
		if (str == "INSERT" || str == "insert")
		{
			cin >> pos >> val;
			tree.addValue(pos, val);
		}
		else if (str == "SUM" || str == "sum")
		{
			cin >> beg >> end;
			cout << tree.getSum(beg, end) << endl;
		}
		else break;
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值