一、解决问题
区间最值和区间求和问题
力扣相关题目:
二、线段树定义
平衡二叉树,数组中的元素都存储在叶子结点中,如图是一个求区间最大值的线段树。
已知数组arr[11,5,3,7,8,2] ,树的高度与数组的长度关系为:
为了方便我们用代码实现线段树,将创建的数为满二叉树,如下图举例
三、实现线段树,并查询区间值
T[] data存储传入的原数组
T[] treeData存储构建的平衡二叉树
Merge<T> merge 融合器,表示线段树中节点值的计算方式
Merge接口:
public interface Merge<T> {
T merge(T v1,T v2);
}
线段树:
import java.util.Arrays;
public class SegmentTree<T>{
//原数组
private T[] data;
//构建的平衡二叉树的数组
private T[] treeData;
private Merge<T> merge;
public SegmentTree(T[] arr,Merge<T> merge){
// 入参判断
if (arr==null||arr.length==0){
return;
}
this.merge = merge;
//将数组赋值到我们的原数组中
this.data = Arrays.copyOf(arr,arr.length);
//计算树的高度
int h = (int)Math.ceil(Math.log10(arr.length)/Math.log10(2)+1);
//平衡二叉树节点个数
int length = (int)Math.pow(2,h)-1;
//初始化树
this.treeData = (T[]) new Object[length];
// 构建平衡二叉树
this.buildingSegmentTree(0,arr.length-1,0);
}
/**
* 构建平衡二叉树
* @param left 原数组的左边索引
* @param right 原数组的右边索引
* @param index 构建树的索引
*/
private void buildingSegmentTree(int left,int right,int index){
// 递归终止条件
if (left==right){
this.treeData[index] = this.data[left];
return;
}
// 递归操作
int mid = left+(right-left)/2;
buildingSegmentTree(left,mid,2*index+1);
buildingSegmentTree(mid+1,right,2*index+2);
//计算当前节点的值
this.treeData[index] = this.merge.merge(this.treeData[2*index+1],this.treeData[2*index+2]);
}
//查询
public T query(int from,int to){
if (from<0||to>this.data.length||to<from){
return null;
}
return query(0,this.data.length-1,0,from,to);
}
/**
*
* @param left 原数组的左位置
* @param right 原数组的右位置
* @param index 平衡二叉树的中对应节点的索引
* @param from 所求索引的开始位置
* @param to 所求索引的结束位置
* @return
*/
private T query(int left,int right,int index,int from,int to){
//找到区间
if (left==from&&right==to){
return this.treeData[index];
}
int mid = left + (right-left)/2;
if (to<=mid){//去左找
return query(left,mid,index*2+1,from,to);
}else if (from>mid){//去右找
return query(mid+1,right,index*2+2,from,to);
}else {//两遍都有
T leftVal = query(left,mid,index*2+1,from,mid);
T rightVal = query(mid+1,right,index*2+2,mid+1,to);
return this.merge.merge(leftVal,rightVal);
}
}
public static void main(String[] args) {
Integer[] arr = {1,3,5,7,9,11};
SegmentTree<Integer> tree = new SegmentTree<Integer>(arr,(v1,v2)->v1>v2?v1:v2);
int res = tree.query(2,4);
System.out.println(res);
}
}
测试:
public static void main(String[] args) {
Integer[] arr = {11,5,3,6,7,8,2};
SegmentTree<Integer> tree = new SegmentTree<Integer>(arr,(v1,v2)->v1>v2?v1:v2);
int res = tree.query(2,4);
System.out.println(res);//7
}