线段树【java实现】

一、解决问题

区间最值和区间求和问题

力扣相关题目: 

​​​​​​303. 区域和检索 - 数组不可变

729. 我的日程安排表 I

二、线段树定义

平衡二叉树,数组中的元素都存储在叶子结点中,如图是一个求区间最大值的线段树。

已知数组arr[11,5,3,7,8,2] ,树的高度与数组的长度关系为:

为了方便我们用代码实现线段树,将创建的数为满二叉树,如下图举例

线段树【java实现】_第1张图片

三、实现线段树,并查询区间值

T[] data存储传入的原数组

T[] treeData存储构建的平衡二叉树

Merge merge 融合器,表示线段树中节点值的计算方式

 Merge接口:

public interface Merge {
    T merge(T v1,T v2);
}

线段树: 

import java.util.Arrays;

public class SegmentTree{

    //原数组
    private T[] data;
    //构建的平衡二叉树的数组
    private T[] treeData;

    private Merge merge;

    public SegmentTree(T[] arr,Merge 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||tomid){//去右找
            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 tree = new SegmentTree(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 tree = new SegmentTree(arr,(v1,v2)->v1>v2?v1:v2);
        int res =  tree.query(2,4);
        System.out.println(res);//7
    }

 

你可能感兴趣的:(数据结构,算法,线段树)