数据结构实现 7.1:线段树(C++版)

1. 概念及基本框架

线段树 是一种二叉树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

线段树

如上图中,每个结点可以存一些这个区间内的元素的性质,比如:和、最大值、最小值……通过不同区间的组合,我们可以访问到特定的区间元素的性质。因为划分区间我们采用二分的方法,而且左边的元素数目大于等于右边的元素数目,所以线段树本质上也是一棵完全二叉树。
注:这里线段树的每个结点存的只是一个元素,即这个区间元素的性质。
这里给出线段树大体框架:

template <class T>
class SegmentTree{
   
public:
	SegmentTree(T *arr, int len){
   
		m_data = new T[len];
		for (int i = 0; i < len; ++i){
   
			m_data[i] = arr[i];
		}
		m_size = len;
		m_tree = new T[4 * len];
		m_treeSize = 0;
		buildSegmentTree(0, 0, m_size - 1);
	}
	...
private:
	T *m_data;
	int m_size;
	T *m_tree;
	int m_treeSize;
	MergerNew<T> m;
};

m_data 用来接收线段树中原来的 n 个元素。
m_size 表示线段树的原数据大小。
m_tree 用来存储线段树每个结点的数据。
m_treeSize 表示线段树结点的数目。
m 可以认为内部有一个函数包可供我们调用,后面会详细讲述。
同样,为了保护数据,这些变量都放在 private 区。
buildSegmentTree 是一个线段树的构建函数,下面会详细讲述。
注:构造函数中,我们发现线段树结点提供了 4n 个,这是为了防止越界。
接下来我们就对线段树的构建、查询以及一些其他基本操作用代码去实现。

2. 基本操作程序实现

2.1 构建操作

为了不断划分区间,我们需要的到完全二叉树中,一个结点左右子结点的索引,这一点很类似于 6.1最大二叉堆 的做法。原理不再赘述,给出其实现函数:

template <class T>
class SegmentTree{
   
	...
private:
	//返回完全二叉树中,一个结点左子结点的索引
	int leftChild(const int index) const {
   
		return 2 * index + 1;
	}
	//返回完全二叉树中,一个结点右子结点的索引
	int rightChild(const int index) const {
   
		return 2 * (index + 1);
	}
	...
};

有了索引,我们就可以不断地进行区间划分,进而构建出一棵线段树。构建的实现函数如下:

template <class T>
class SegmentTree{
   
	...
private:
	...
	//在treeIndex位置创建表示区间[left...right]的线段树
	void buildSegmentTree(const int treeIndex,const int left,const int right){
   
		m_treeSize++;
		if (left == right){
   
			m_tree[treeIndex] = m_data[left];
			return;
		}
		int leftTreeIndex = leftChild(treeIndex);
		int rightTreeIndex = rightChild(treeIndex)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值