线段树

线段树

什么是线段树?

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。

如果区间有n个元素,数组表示需要有多少个节点?
需要4n个的空间

我们的线段树不考虑添加元素,即区间固定
使用4n的静态空间即可

创建线段树的相关代码

package SegmentTree;

public class SegmentTree<E> {

	private E[] tree;
	private E[] data;
	private Merger<E> merger;
	
	public SegmentTree(E[] arr,Merger<E> merger) {
		
		this.merger = merger;
		
		data =(E[]) new Object[arr.length];
		for(int i = 0;i < arr.length ; i++)
		data[i] = arr[i];	
		
		tree =(E[]) new Object[4*arr.length];
		bulidSegmentTree(0,0,data.length - 1);
	}
	
	//在treeIndex的位置创建表示区间[l....r]的线段树
	private void bulidSegmentTree(int treeIndex,int l,int r) {
		
		if(l == r) {
			tree[treeIndex] = data[l];
			return;
		}
		
		int leftTreeIndex = leftChild(treeIndex);
		int rightTreeIndex = rightChild(treeIndex);
		
		int mid = l + (r-l)/2;
		bulidSegmentTree(leftTreeIndex, l,mid);
		bulidSegmentTree(rightTreeIndex, mid+1, r);
		
		tree[treeIndex] = merger.merge(tree[leftTreeIndex] , tree[rightTreeIndex]);
	}

	public int getSize() {
		return data.length;
	}
	
	public E get(int index) {
		if(index < 0 || index >= data.length)
			throw new IllegalArgumentException("Index is illegal");
		return data[index];
	}
	
	//返回完全二叉树的数组表示,一个索引所表示的元素的左孩子节点的索引
	private int leftChild(int index) {
		return 2*index +1;
	}
	
	private int rightChild(int index) {
		return 2*index +2;
	}
}

线段树中的区间查询

	
public E query(int queryL,int queryR) {
		if(queryL < 0 || queryL >= data.length || queryR < 0 || queryR >= data.length || queryL > queryR)
			throw new IllegalArgumentException("Index is illegal");
		
		return query(0,0,data.length - 1,queryL,queryR);
	}
	//在以treeIndex为根的线段树中[l...r]的范围里,搜索区间[queryL...queryR]的值
	private E query(int treeIndex,int l,int r,int queryL,int queryR) {
		
		if(l == queryL && r == queryR) 
			return tree[treeIndex];
			
			int mid = l+(r-l)/2;
			int leftTreeIndex = leftChild(treeIndex);
			int rightTreeIndex = rightChild(treeIndex);
			
			if(queryL >= mid +1)
				return query(rightTreeIndex, mid+1,r,queryL,queryR);
			else if(queryR <= mid)
				return query(leftTreeIndex, l,mid,queryL,queryR);
			
			E leftResult = query(leftTreeIndex,l,mid,queryL,mid);
			E rightResult = query(rightTreeIndex,mid+1,r,mid+1,queryR);
			return merger.merge(leftResult, rightResult);
			
		
	}
	

测试代码

public class Main {
	public static void main(String[] args) {
		
		Integer[] nums = {-2,0,3,-5,2,-1};
		SegmentTree<Integer> segTree = new SegmentTree<>(nums, (a,b) -> a+b);
		
		System.out.println(segTree.query(0, 2));
		System.out.println(segTree.query(2, 5));
		System.out.println(segTree.query(0, 5));
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值