首页 > 其他 > 详细

线段树

时间:2015-10-21 22:25:43      阅读:399      评论:0      收藏:0      [点我收藏+]

  线段树是一棵完美二叉树,树上的每个节点都维护一个区间。根维护的是整个区间,每个节点维护的是父亲的区间二等分后的其中一个子区间。当有n个元素时,对区间的操作可以在O(logn)的时间内完成。

  所以,线段树是擅长处理区间的!

  从网上找了一个图:

  技术分享

RMQ(range minimum query)问题:

  在给定数列a0,a1...an,给定s和t,线段树可以求as...at的最值,以求最小值为例,如下图:

  技术分享

  每个节点维护对应区间的最小值,例如根节点维护的是下标1到8的最小值,左子树维护的是1到4,右子书维护的是5到6,以此类推。

  建树时,父节点取左右子节点的较小者。我比较喜欢用数组建树,因为非常简单清晰,下面是初始化线段树的代码:

  

1 #define max 999999999
2 int k,n,tree[10005];//n这里是数列里数字的个数
3 void init(){
4     k=1;//k这里是树最后一层的叶子个数
5     while(k<n)//除第一层外,树的每一层都有2的n次方个节点,所以这里求的是k大于n的最小节点数
6         k<<=1;//输入的数字个数n可能小于最下面一层的叶子数
7     for(int i=1;i<=2*k-1;i++)//2*k-1是整个树节点的个数,全部设置为max,反正父节点取的是较小者
8         tree[i]=max;
9 }

  n小于k时,树最后一层的其他值已经是max,所以不影响父节点,下面是线段树每插入一个值的更新:

1 void update(int pos,int val){//pos是树的下标,val是数的值
2     pos+=k-1;//这里数组下标是从1到n,树的下标也是从1到n,这就是叶子节点与数组下标的对应关系,大家可以画一画
3     tree[pos]=val;
4     while(k>1){
5         pos/=2;//父节点
6         tree[pos]=tree[pos*2]<tree[pos*2+1]?tree[pos*2]:tree[pos*2+1];
7     }
8 }

  下面比较关键的是给定下标区间查找,我会在注释里说明:

 1 //调用时query(输入a,输入b,1,l(英文l,不是数1),n)
 2 int query(int a,int b,int pos,int l,int r){//a和b是想要查找的下标区间,l和r是当前节点维护的下标区间,pos是当前节点下标
 3     if(a>r||b<l)
 4         return max;//当想查找的区间完全超出当前节点维护的区间是,直接返回一个很大的数,反正是取最小
 5     if(r-l==1){//这里很麻烦,有一种情况是,想查找的区间与维护的区间仅有一条边重合,例如想查找的是4、5,当前区间是5、6,
 6         if(b==l)//这样,当到了当前区间左右差值为1时,不能向下继续了所以需要返回重合边所在的叶子的值(这里我尽量说明白,大家画一下会清楚很多)
 7             return tree[2*pos];
 8         if(a==r)
 9             return tree[2*pos+1];
10     }
11     if(a<=l&&b>=r)//查找终结的条件就是想查找的区间大于节点维护的区间
12         return tree[pos];
13     else{
14         int vl=query(a,b,pos*2,l,(l+r)/2);//左节点
15         int vr=query(a,b,pos*2+1,(l+r)/2+1,r);//右节点
16         return vl<vr?vl:vr;//返回较小
17     }
18 }

  OK,到这里,基本的算法就实现了,注意一下树的大小一定要合适。第一篇博客,有些地方想讲清楚可能讲的还不透彻,甚至里面会有错误,等我的理解更加深入之后,会继续修改的。

  

线段树

原文:http://www.cnblogs.com/zqy123/p/4899197.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!