区间树和线段树
来源:互联网 发布:stc单片机引脚功能图 编辑:程序博客网 时间:2024/06/04 19:27
注意:区间树和线段树不一样哦,线段树是一种特殊的区间树。
区间树:
区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点。通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成。相比于基础的红黑树数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值。逻辑结构如下所示:
区间树具有和红黑树一样的性质,并且区间树的基础操作和红黑树的基础操作一样。(具体红黑树的操作,参见http://blog.csdn.net/v_JULY_v/article/details/6105630)
红黑树的性质如下:(一定要牢记哦!)
(1)节点要么是红色的,要么是黑色的
(2)根节点是黑色的
(3)每个叶节点(即空节点)是黑色的
(4)若节点是红色的,则它的孩子节点必为黑色
(5)对每个节点,从该节点到它的子孙叶子节点的所有路径上包含相同的黑色节点。
线段树:线段树是一种平衡二叉查找树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。主要的处理思想是基于分治的思想。它的逻辑结构如下:
设根节点的区间为[a,b),区间长度为L = b - a,线段树的性质:
(1)线段树是一个平衡树,树的高度为log(L)
(2)线段树把区间上的任意长度为L的线段都分成不超过2log(L)线段的并
线段树基础存储结构如下:(这里使用数组模拟指针,类似堆的存储结构)
struct tag_LineSegNode{int left;//区间左单点int right;//区间右单点int mid;//区间中间值
int cover;<span style="white-space:pre"></span> //是否覆盖(<span style="font-size: 14px; text-indent: 28px; background-color: rgb(255, 0, 0);">注意:线段树的节点信息根据具体的应用需求添加相应的数据字段。)</span> }; typedef struct tag_LineSegNode LSNode;
根据线段树的性质可知,线段树的节点个数大于2*L,这里设置线段树的节点个数为LSNode node[3 * L];
线段树的操作主要有:
(1)创建线段树
void BuildLineSegTree(int left,int right,int nodeNum){ node[nodeNum].left = left; node[nodeNum].right = right; node[nodeNum].mid = left + (right - left) / 2; node[nodeNum].cover = 0; //判断是否是叶子节点 if(left != right - 1) { BuildLineSegTree(left,node[nodeNum].mid,2 * nodeNum); BuildLineSegTree(node[nodeNum].mid,right,2 * nodeNum + 1); }}
(2)插入线段树
void InsertLineSegTree(int left,int right,int nodeNum){ //判断区间是否完全覆盖 if(node[nodeNum].left == left && node[nodeNum].right == right) { node[nodeNum].cover += 1; return ; } if(right <= node[nodeNum].mid) { //线段在左子树上 return InsertLineSegTree(left,right,2 * nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树上 return InsertLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树上,一部分在右子树上 return InsertLineSegTree(left,node[nodeNum].mid,2 * nodeNum) || InsertLineSegTree(node[nodeNum].mid,right,2 * nodeNum + 1); }}(3)查询线段树
int SearchLineSegTree(int left,int right,int nodeNum){ if(node[nodeNum].left == left && node[nodeNum].right == right) { //线段完全覆盖,若该线段存在则返回1,否则返回0 return node[nodeNum].cover; } if(right <= node[nodeNum].mid) { //线段在左子树 return SearchLineSegTree(left,right,2 * nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树 return SearchLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树,一部分在右子树 return SearchLineSegTree(left,node[nodeNum].mid,2 * nodeNum) && SearchLineSegTree(node[nodeNum].mid,right,2 * nodeNum + 1); }}
(4)删除线段树
int DeleteLineSegTree(int left,int right,int nodeNum){ if(node[nodeNum].left == left && node[nodeNum].right == right) { //线段完全覆盖,若该线段存在则返回1,否则返回0 int ret = node[nodeNum].cover; node[nodeNum].cover = node[nodeNum].cover > 0 ? node[nodeNum].cover - 1 : 0; return ret; } if(right <= node[nodeNum].mid) { //线段在左子树 return DeleteLineSegTree(left,right,2 * nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树 return DeleteLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树,一部分在右子树 return DeleteLineSegTree(left,node[nodeNum].mid,2 * nodeNum) && DeleteLineSegTree(node[nodeNum].mid,right,2 * nodeNum + 1); }}
线段树在一些具体的应用中,需要对输入的数据进行离散化,以减小线段树的大小,此时需要注意离散前和离散后的数据对应。此外,在某些应用中,需要使用lazy思想,在一些操作中先不对线段树进行更新,而是推迟到查找的过程中,在查找的过程中进行更新。
具体的应用见本博客的后续部分。。。。敬请关注哦!
- 区间树和线段树
- 线段树区间和最大值
- 线段树-区间单个点更新-区间和-区间最大
- 线段树求区间和(单点更新)
- 线段树-动态查询区间最大和
- uva1400 区间最大连续和 线段树
- 线段树单点更新和区间查询
- 【最小区间问题】 RQM 和 线段树
- 线段树求区间和模板
- 线段树 单点更新求区间和
- spojGSS1 线段树维护区间和最大值
- 线段树 点更新 区间和 模板
- [CodeVS1082] 线段树练习3(区间修改+询问区间和)
- 【线段树-区间更新求区间和】CDOJ 1057
- POJ 3468(线段树,区间加减 询问区间和)
- HihoCoder 1078(线段树,区间覆盖 询问区间和)
- 线段树模板(区间和+区间最大值 + LAZY标记)
- 线段树 区间合并
- linux编程--shell的判断和比较
- Java异常处理机制
- 求凸包面积
- Hibernate(三)Hibernate常用API详解及源码分析
- mongodb-elasticsearch-rive源码解析
- 区间树和线段树
- 用Eclipse调试ndk编译的c程序
- Hibernate(四)Hibernate常用配置文件详解
- 编辑框中添加一个控件及程序编辑
- 网桥系列 1
- c# MVC 跳转页面
- Unity 3D——四元数的应用
- Android 实现书籍翻页效果----源码篇
- 最长上升子序列。百炼2757 2种方法