Data Structure: Segment Tree 线段树
来源:互联网 发布:mac按键失灵 编辑:程序博客网 时间:2024/06/06 22:15
线段树主要用于Range Query. 适用问题在:这个大区域的某个子区间最小值,这个大区间的某个子区间的和等等。线段树的某个叶子节点都是代表一个大区间的元素。
为什么要使用线段树?
那先让我们看看,如果不使用线段树,上述的求某个子区间最小值的问题该如何解决。
方案1:每次query都去遍历一次子区间。如果有m次查询,有n个元素的话,时间复杂度就是O(mn)。
方案2:设置一个matrix,x, y 两个方向都是区间的元素。(0, 3)代表从0到3的最小值。那么建立这么一个matrix需要O(n^2)的空间复杂度和时间复杂度。查询只需要O(1)。但是如果有update就十分麻烦。
线段树的优点在于:
O(n)的时间负责度和空间复杂度去建立。
O(logn)的查询复杂度。
首先,我们需要知道线段树的几个性质:
1)线段树是一棵完全二叉树;
2)基于性质1,线段树适合使用数组进行存储,因为中间空值不多;
3)存储线段树的数组长度 = ceil (大于原数组长度的2的次方数) * 2 - 1。譬如,原数组的长度是4,4刚好是2的2次方。所以长度 = 4 * 2 - 1 = 7. 但原数组长度是5,则存储数组长度是:8 * 2 - 1 = 15.
所以,任何数组的线段树存储数组的长度都不超过4n,n是原来数组的长度。建立线段树数组时候,用上这个性质。
这里,我们稍微温习一下使用数组来存储完全二叉树的两个例子:1)堆 2)线段树
利用数组来存储树有两个很重要的性质:
1)当前节点index为i,其两个孩子的index为:2 * i + 1(左), 2 * i + 2(右)
2) 反之,父节点的index为:(i - 1) / 2,截尾得到int.
线段树的建立逻辑和查询逻辑都是依据线段树的实际意义建立的。线段树的每个节点代表一个区间,叶子节点的区间是左右两个值相等,代表一个元素。父节点代表两个子节点区间的并集。直到根节点代表整个区间。
利用上述实际意义,建立线段树的逻辑是:
1)递归建立;
2)终止条件:区间左右两个值相等,直接得到当前局部最优解
3)否则,二分递归;
4)得到最小情况后,回归得到当前局部最优解(类似动归的思想)
查询的逻辑在代码中有所体现:
Totally match:当前的节点代表的区间 [start, end] 满足 qStart <= start && end <= qEnd,返回当前节点的值。
No match: start > qEnd || end < qStart
Partical match:则是不满足上述两种情况。
代码如下:
public class Solution {// range minimum query// only the current root is relative to segment tree.public void createSeg(int[] array, int[] seg, int start, int end, int curRoot) {if (start == end) {seg[curRoot] = array[start];// leavesreturn;}int mid = start + (end - start) / 2;createSeg(array, seg, start, mid, 2 * curRoot + 1);createSeg(array, seg, mid + 1, end, 2 * curRoot + 2);seg[curRoot] = Math.min(seg[2 * curRoot + 1], seg[2 * curRoot + 2]);}public int rangeQuery(int[] seg, int qStart, int qEnd, int start, int end, int curRoot) {// think about 3 kinds // 1) Total match. Current [start, end] is total match qStart and qEnd or is totally a subset of qStart and qEnd. Return its value. // 2) Not match. None of elements of current [start, end] is in [qStart, qEnd], return INT_MAXVALUE// 3) Partial match. Some of current [start, end] are in [qStart, qEnd] while the others are not. Continue recursion to its children. if (start >= qStart && end <= qEnd) {return seg[curRoot];}if (start > qEnd || end < qStart) {return Integer.MAX_VALUE;}int mid = start + (end - start) / 2;return Math.min(rangeQuery(seg, qStart, qEnd, start, mid, 2 * curRoot + 1), rangeQuery(seg, qStart, qEnd, mid + 1, end, 2 * curRoot + 2));}public static void main(String[] args) {int[] array = new int[]{-1,1,2,4,-2,6};Solution ins = new Solution();int n = array.length;// Maximum length of seg = 4*n;int[] seg = new int[4 * n];ins.createSeg(array, seg, 0, 5, 0);System.out.println(ins.rangeQuery(seg, 0, 3, 0, 5, 0));}}
复杂度分析:
* Time complexity to create segment tree is O(n) since new array will be at max 4n size
* Space complexity to create segment tree is O(n) since new array will be at max 4n size
* Time complexity to search in segment tree is O(logn) since you would at max travel 4 depths
* Time complexity to update in segment tree is O(logn)
- Data Structure: Segment Tree 线段树
- 线段树(segment tree)
- 线段树(segment tree)
- 线段树(segment tree)
- 线段树(segment tree)
- 线段树(segment tree)
- 线段树(segment tree)
- segment tree(线段树)
- hdu4217 Data Structure? 线段树
- hdu Data Structure? 线段树
- hdu4217 Data Structure?(线段树)
- 线段树(segment tree)
- 线段树(segment tree) code
- 浅谈线段树 Segment Tree
- Segment Tree-线段树学习
- XTU1238:Segment Tree(线段树)
- XTU1238:Segment Tree(线段树)
- 线段树(Segment Tree)
- 财富杂志推荐的75本必读书
- 高通Qualcomm平台lk(light kernel)启动流程2——aboot_init()
- ActiveMQ监控队列状态报javax.management.InstanceNotFoundException
- Oratop工具_实时数据库性能监控工具
- java 获取 T.class
- Data Structure: Segment Tree 线段树
- mapreduce编程模型之WritableComparator
- 【汇总】java常见面试题汇总
- 助解“中等收入陷阱”金融是否大有可为
- android json在线解析
- Oracle SQL
- Javaweb 文件上传到服务器
- jQuery判断元素是否存在的可靠方法
- springboot整合Quartz实现动态配置定时任务