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

线段树(一)

时间:2014-12-02 22:22:48      阅读:278      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   io   ar   color   os   sp   java   

问题:

先抛出一个问题,坐标轴上有若干线段,现在给定若干个点,对于每个点,求出包含点的线段的数量

如果用常规的解法,时间复杂度是O(mn),空间复杂度是O(m + n)

能不能降低一下时间复杂度呢?答案是肯定的,这些线段里有大量相交或者覆盖的线段,而上面的解法显然没有利用这些信息,导致时间复杂度较高,现在我们引入

一个数据结构,线段树(Segment Tree),从Wikipedia抄过来定义如下:

In computer science, a segment tree is a tree data structure for storing intervals, or segments. It allows querying which of the 
stored segments contain a given point. It can be implemented as a dynamic structure. A similar data structure is the interval tree.

第一次看我也是一头雾水,什么也没说嘛,下面用一张图解释一下:

A. 建树

bubuko.com,布布扣

 

给出8条线段,S[1-8],区间分别为[1,3],[2,4],[3,5],[4,6],[7,8],[7,9],[9,10],[8,10],总区间为[1,10],一棵线段树要覆盖区间,因此用区间[1,10]

建立一棵线段树,如上图,可以看出,线段树是一棵二叉平衡树,简单性质如下:

    1. 对于非叶子节点:r[a,b](a < b) r的左儿子节点的区间为[a,(a + b) / 2];r的右儿子节点的区间为[(a + b) / 2 + 1, b]

    2. 叶子节点对应一个点,也即r[a,b](a = b)

 

A. 插入线段

那么建立起这样一棵树后,怎么插入一条线段呢?方法很简单,以插入S8为例,看图:

bubuko.com,布布扣

可以看出,方法很简单:

1. 从根节点r(a,b)开始, 待插线段s(c,d)

    1.0 如果a==b,转到2

    1.1 如果d <= (a + b) / 2,以r的左孩子为根,转到1

    1.2 如果c > (a + b) / 2,以r的右孩子为根,转到1

    1.3 否则搜索r的左孩子和右孩子

2. 节点的值+1

C. 查询

最后查询某个点的包含次数,就非常简单了,沿着根节点搜索到叶子节点,对应的叶子节点的值即为包含次数

 

给出代码:

 1 /*建树*/
 2 void build_ST(int i, int left, int right) {
 3     st[i].left = left;
 4     st[i].right = right;
 5     if(left == right) {
 6         st[i].count = 0;
 7         return;    
 8     }   
 9     build_ST(i * 2, left, (left + right) / 2); 
10     build_ST(i * 2 + 1, (left + right) / 2 + 1, right);
11 }
 1 /*插入线段*/
 2 void insert_ST(int i, int left, int right) {
 3     int l = st[i].left;
 4     int r = st[i].right;
 5     if(l == r) {
 6         st[i].count++
 7     }
 8     else if(right <= (r + l) / 2) {
 9         insert_ST(i * 2, left, right);
10     }
11     else if(left > (r + l) / 2) {
12         insert_ST(i * 2 + 1, left, right);
13     }
14     else {
15         insert_ST(i * 2, left, right);
16         insert_ST(i * 2 + 1, left, right);
17     }
18 }
 1 int query_ST(int i, int value) {
 2     int l = st[i].left;
 3     int r = st[i].right;
 4     if(l == r) 
 5         return st[i].count;
 6     else if(value <= (r + l) / 2)
 7         return query_ST(i * 2, value);
 8     else
 9         return query_ST(i * 2 + 1, value);
10 }

 

最后看一下复杂度:

操作 时间复杂度 空间复杂度
建树 O(points) O(points)
插入

O(points)

 
查询 O(logpoints)  

 

 

 

 

 

 

由于本人水平有限,文中难免有不当和错误指出,欢迎大家批评指正,愿共同进步!!!

 

线段树(一)

标签:des   style   blog   io   ar   color   os   sp   java   

原文地址:http://www.cnblogs.com/zhuoyuan/p/4138496.html

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