• 线段树【java实现】


    一、解决问题

    区间最值和区间求和问题

    力扣相关题目: 

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

    729. 我的日程安排表 I

    二、线段树定义

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

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

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

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

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

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

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

     Merge接口:

    1. public interface Merge {
    2. T merge(T v1,T v2);
    3. }

    线段树: 

    1. import java.util.Arrays;
    2. public class SegmentTree{
    3. //原数组
    4. private T[] data;
    5. //构建的平衡二叉树的数组
    6. private T[] treeData;
    7. private Merge merge;
    8. public SegmentTree(T[] arr,Merge merge){
    9. // 入参判断
    10. if (arr==null||arr.length==0){
    11. return;
    12. }
    13. this.merge = merge;
    14. //将数组赋值到我们的原数组中
    15. this.data = Arrays.copyOf(arr,arr.length);
    16. //计算树的高度
    17. int h = (int)Math.ceil(Math.log10(arr.length)/Math.log10(2)+1);
    18. //平衡二叉树节点个数
    19. int length = (int)Math.pow(2,h)-1;
    20. //初始化树
    21. this.treeData = (T[]) new Object[length];
    22. // 构建平衡二叉树
    23. this.buildingSegmentTree(0,arr.length-1,0);
    24. }
    25. /**
    26. * 构建平衡二叉树
    27. * @param left 原数组的左边索引
    28. * @param right 原数组的右边索引
    29. * @param index 构建树的索引
    30. */
    31. private void buildingSegmentTree(int left,int right,int index){
    32. // 递归终止条件
    33. if (left==right){
    34. this.treeData[index] = this.data[left];
    35. return;
    36. }
    37. // 递归操作
    38. int mid = left+(right-left)/2;
    39. buildingSegmentTree(left,mid,2*index+1);
    40. buildingSegmentTree(mid+1,right,2*index+2);
    41. //计算当前节点的值
    42. this.treeData[index] = this.merge.merge(this.treeData[2*index+1],this.treeData[2*index+2]);
    43. }
    44. //查询
    45. public T query(int from,int to){
    46. if (from<0||to>this.data.length||to
    47. return null;
    48. }
    49. return query(0,this.data.length-1,0,from,to);
    50. }
    51. /**
    52. *
    53. * @param left 原数组的左位置
    54. * @param right 原数组的右位置
    55. * @param index 平衡二叉树的中对应节点的索引
    56. * @param from 所求索引的开始位置
    57. * @param to 所求索引的结束位置
    58. * @return
    59. */
    60. private T query(int left,int right,int index,int from,int to){
    61. //找到区间
    62. if (left==from&&right==to){
    63. return this.treeData[index];
    64. }
    65. int mid = left + (right-left)/2;
    66. if (to<=mid){//去左找
    67. return query(left,mid,index*2+1,from,to);
    68. }else if (from>mid){//去右找
    69. return query(mid+1,right,index*2+2,from,to);
    70. }else {//两遍都有
    71. T leftVal = query(left,mid,index*2+1,from,mid);
    72. T rightVal = query(mid+1,right,index*2+2,mid+1,to);
    73. return this.merge.merge(leftVal,rightVal);
    74. }
    75. }
    76. public static void main(String[] args) {
    77. Integer[] arr = {1,3,5,7,9,11};
    78. SegmentTree tree = new SegmentTree(arr,(v1,v2)->v1>v2?v1:v2);
    79. int res = tree.query(2,4);
    80. System.out.println(res);
    81. }
    82. }

    测试:

    1. public static void main(String[] args) {
    2. Integer[] arr = {11,5,3,6,7,8,2};
    3. SegmentTree tree = new SegmentTree(arr,(v1,v2)->v1>v2?v1:v2);
    4. int res = tree.query(2,4);
    5. System.out.println(res);//7
    6. }

     

  • 相关阅读:
    微信小程序微信用户授权登录怎么在小程序上和钉钉相关联
    Kotlin(五)null操作
    Spring()
    冲压模具在线检测技术,解决过哪些问题?
    Day 01 web前端基础知识
    五分钟,Docker安装kafka 3.5,kafka-map图形化管理工具
    NoSql之Redis整数集合(intset)源码探究
    mysql虚拟列问题
    joi:定义多个自定义错误信息
    【Java 进阶篇】JavaScript 动态表格案例
  • 原文地址:https://blog.csdn.net/weixin_63541561/article/details/133890172