码迷,mamicode.com
首页 > 其他好文 > 详细

线段树总结一【转】

时间:2014-08-12 02:58:23      阅读:270      评论:0      收藏:0      [点我收藏+]

标签:blog   http   使用   os   strong   数据   2014   ar   

数据结构:线段树 【转】

http://blog.csdn.net/wypblog/article/details/8219727

一、线段树基本概念

           线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
    对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

    使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

   性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

bubuko.com,布布扣

二、线段树的存储数据结构

    由上面的图可以看出,存储一颗线段树和二叉树有点类似,需要左孩子和右孩子节点,另外,为了存储每条线段出现的次数,所以一般会加上计数的元素,其具体如下:

bubuko.com,布布扣
1 struct Node         // 线段树
2 {
3     int left;
4     int right;
5     int counter;
6 }segTree[4*BORDER]; 
bubuko.com,布布扣

其中,;left代表左端点、right代表右端点,counter代表每条线段出现的次数,BORDE代表线段端点坐标不超过100。由上面的性质可以知道,我们需要4倍的空间来存储。

三、线段树支持的操作

一颗线段树至少支持以下四个操作:

    • void construct(int index, int lef, int rig),构建线段树 根节点开始构建区间[lef,rig]的线段树
    • void insert(int index, int start, int end),插入线段[start,end]到线段树, 同时计数区间次数
    • int query(int index, int x),查询点x的出现次数,从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数
    • void delete_ (int c , int d, int index),从线段树中删除线段[c,d]

 

具体操作如下:

1、线段树的创建

bubuko.com,布布扣

/* 构建线段树 根节点开始构建区间[lef,rig]的线段树*/
void construct(int index, int lef, int rig)
{
segTree[index].left = lef;
segTree[index].right = rig;
if(lef == rig) // 叶节点
{
segTree[index].counter = 0;
return;
}
int mid = (lef+rig) >> 1;
construct((index<<1)+1, lef, mid);
construct((index<<1)+2, mid+1, rig);
segTree[index].counter = 0;
}

bubuko.com,布布扣
 1 /* 构建线段树 根节点开始构建区间[lef,rig]的线段树*/
 2 void construct(int index, int lef, int rig)
 3 {
 4     segTree[index].left = lef;
 5     segTree[index].right = rig;
 6     if(lef == rig)   // 叶节点
 7     {
 8         segTree[index].counter = 0;
 9         return;
10     }
11     int mid = (lef+rig) >> 1;
12     construct((index<<1)+1, lef, mid);
13     construct((index<<1)+2, mid+1, rig);
14     segTree[index].counter = 0;
15 }
bubuko.com,布布扣

2、线段树的元素插入

bubuko.com,布布扣

/* 插入线段[start,end]到线段树, 同时计数区间次数 */
void insert(int index, int start, int end)
{
if(segTree[index].left == start && segTree[index].right == end)
{
++segTree[index].counter;
return;
}
int mid = (segTree[index].left + segTree[index].right) >> 1;
if(end <= mid)//左子树
{
insert((index<<1)+1, start, end);
}else if(start > mid)//右子树
{
insert((index<<1)+2, start, end);
}else//分开来了
{
insert((index<<1)+1, start, mid);
insert((index<<1)+2, mid+1, end);
}
}

bubuko.com,布布扣
 1 /* 插入线段[start,end]到线段树, 同时计数区间次数 */
 2 void insert(int index, int start, int end)
 3 {
 4     if(segTree[index].left == start && segTree[index].right == end)
 5     {
 6         ++segTree[index].counter;
 7         return;
 8     }
 9     int mid = (segTree[index].left + segTree[index].right) >> 1;
10     if(end <= mid)//左子树 
11     {
12         insert((index<<1)+1, start, end);
13     }else if(start > mid)//右子树 
14     {
15         insert((index<<1)+2, start, end);
16     }else//分开来了 
17     {
18         insert((index<<1)+1, start, mid);
19         insert((index<<1)+2, mid+1, end);
20     }
21 }
bubuko.com,布布扣

3、线段树的元素查找

bubuko.com,布布扣

/* 查询点x的出现次数
* 从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数
*/
int query(int index, int x)
{
if(segTree[index].left == segTree[index].right) // 走到叶子,返回
{
return segTree[index].counter;
}
int mid = (segTree[index].left+segTree[index].right) >> 1;
if(x <= mid)
{
return segTree[index].counter + query((index<<1)+1,x);
}
return segTree[index].counter + query((index<<1)+2,x);
}

bubuko.com,布布扣
 1 /* 查询点x的出现次数 
 2  * 从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数
 3  */
 4 int query(int index, int x)
 5 {
 6     if(segTree[index].left == segTree[index].right) // 走到叶子,返回
 7     {
 8         return segTree[index].counter;
 9     }
10     int mid = (segTree[index].left+segTree[index].right) >> 1;
11     if(x <= mid)
12     {
13         return segTree[index].counter + query((index<<1)+1,x);
14     }
15     return segTree[index].counter + query((index<<1)+2,x);
16 }
bubuko.com,布布扣

4、线段树的元素删除

void delete_ (int c , int d, int index)
{
if(c <= segTree[index].left && d >= segTree[index].right)
segTree[index].counter--;
else
{
if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left);
if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right);
}
}


bubuko.com,布布扣
 1 void  delete_ (int c , int  d, int index)
 2 {
 3        if(c <= segTree[index].left && d >= segTree[index].right) 
 4            segTree[index].counter--;
 5        else 
 6        {
 7           if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left);
 8           if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right);
 9        }
10 } 
bubuko.com,布布扣

四、线段树的应用

  • 区间最值查询问题
  • 连续区间修改或者单节点更新的动态查询问题 
  • 多维空间的动态查询
(转载请注明:http://www.iteblog.com/archives/144,请不要用于商业目的。)

线段树总结一【转】,布布扣,bubuko.com

线段树总结一【转】

标签:blog   http   使用   os   strong   数据   2014   ar   

原文地址:http://www.cnblogs.com/fightfor/p/3906101.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!