线段树解析

概念:

线段树是一种特殊的结构,它每个节点记录着一个区间和这个区间的一个计数,表示此区间出现的次数。

线段树分为构造build部分,插入insert部分,以及查询query部分。其主要的思想就是用空间换时间,来使一些特殊的问题的时间复杂度减少。比如对于一段空间或者一个数字的出现次数,以线段树来查询可以使时间复杂度从乘法减少到log,具体的复杂度分析可以看参考资料1:http://blog.csdn.net/bochuan007/article/details/6713971

举个栗子:

根节点为1-7区间的线段树如下所示:


它build的规则是:根节点部分表示的区间是所有数据的[min,max]部分,令mid = (min + max) / 2,左孩子代表的区间是[min,mid],右孩子代表的区间是[mid + 1, max]。

叶子节点代表的是单个数字,即left == right。

那么我们首先定义一个数据结构,表示线段数中节点元素:

struct Element{//元素结构体维护一个计数、一个左边界和右边界
	int count = 0;
	int left;
	int right;
	Element(int vx, int vy) :left(vx), right(vy){}//构造函数
};
然后,我们再对二叉树本身写一个结构,其中包含了上面所述的元素:

struct Node{//线段树的结点,里面有一个元素结构体以及孩子指针
	Element *e;
	Node* lchild;
	Node* rchild;
	Node(Element *ve) : e(ve), lchild(NULL), rchild(NULL){}
};
那么,线段数的build部分的函数如下:

Node* build(int n, int m){//构造树的方法,输入左、右边界和父结点指针
	Element *te = new Element(n, m);//构造元素结构体
	Node *ret = new Node(te);//构造返回结点
	if (n == m){//说明是叶子节点
		return ret;
	}
	else{//递归构造左右孩子节点
		int mid = (n + m) / 2;
		ret->lchild = build(n, mid);
		ret->rchild = build(mid + 1, m);
	}
	return ret;
}
接下来:线段数的insert插入规则如下:对于插入的区间[n,m],如果线段数节点当前表示区间[l,r]刚好覆盖了[n,m],那么当前节点的count添加上insert的计数部分。

否则,让子节点去接收。

注意,只有当当前节点恰好符合时才会接收,否则不会接收。

举个栗子,比如上面的1-7的线段树,插入[1,4]计数为5的元素,

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值