java 线段树

线段树是一种二叉搜索树,什么叫做二叉搜索树,首先满足二叉树,每个结点度小于等于二,即每个结点最多有两颗子树,何为搜索,我们要知道,线段树的每个结点都存储了一个区间,也可以理解成一个线段,而搜索,就是在这些线段上进行搜索操作得到你想要的答案。在求一个数组任意的区间和的时候,假如这个数组的数据量很大,单纯的for循环已经不能解决问题了,时间复杂度特别高,通常可以使用前缀和数组的方式进行解决问题,使用前缀和求区间和的时间复杂度为O(1),但是当数组进行更新的时候时间复杂度就会为O(n)。而线段树就要可以每次更新以及查询的时间复杂度为O(logN)。

什么是前缀和:例如一个数组:a[1],a[2],a[3]…a[n],前缀和S[i]表示的是该数组的前i项的和,例如S[3] = a[1] + a[2] + a[3],S[i] = a[1] + a[2] + a[3] + … + a[i - 1] + a[i].

引用leetcode进行简单介绍

给定一个整数数组  nums,处理以下类型的多个查询:

计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的 和 ,其中 left <= right
实现 NumArray 类:

NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )
 

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/range-sum-query-immutable

代码

class NumArray {
 int[] sums;
 public  NumArray(int[] nums) {
        int n = nums.length;
        sums = new int[n];
        sums[0]=nums[0];
        for (int i = 1; i < n; i++) {
            sums[i] = sums[i-1] + nums[i];
        }
    }

    public int sumRange(int i, int j) {
        
        return i>0?sums[j] - sums[i-1]:sums[j];
    }
}

复杂度分析

时间复杂度:初始化 O(n),每次检索 O(1),其中 n 是数组 nums 的长度。
初始化需要遍历数组 nums 计算前缀和,时间复杂度是 O(n)O。
每次检索只需要得到两个下标处的前缀和,然后计算差值,时间复杂度是 O(1)。

空间复杂度:O(n),其中 n 是数组ums 的长度。

线段树实例数组

int arr[]=new int[]{1,3,5,7,9,11};

 具体代码

 public static void main(String[] args) {
       int arr[]=new int[]{1,3,5,7,9,11};
       int[] tree=new int[1000];
       tree[0]=0;
       build_tree(arr,tree,0,0,arr.length-1);
//        System.out.println(Arrays.toString(tree));
//        update_tree(arr,tree,0,0,arr.length-1,4,6);
//        System.out.println(Arrays.toString(tree));
        int i = query_tree(arr, tree, 0, 0, arr.length - 1, 2, 5);
        System.out.println(i);
    }
//建造线段树
    public static void build_tree(int arr[],int tree[],int node,int start,int end){
        if(start==end){
            tree[node]=arr[start];
            return;
        }
        int left=2*node+1;
        int right=2*node+2;
        int mid=(start+end)/2;
        build_tree(arr,tree,left,start,mid);
        build_tree(arr,tree,right,mid+1,end);
        tree[node]=tree[left]+tree[right];
    }
//更新某个数值
    public static void update_tree(int arr[],int tree[],int node,int start,int end,int index,int val){
        if(start==end){
            arr[index]=val;
            tree[node]=val;
            return;
        }
        int mid=(start+end)/2;
        int left=2*node+1;
        int right=2*node+2;
        if(index<=mid&&index>=start)
            update_tree(arr,tree,left,start,mid,index,val);
        else
            update_tree(arr,tree,right,mid+1,end,index,val);
        tree[node]=tree[left]+tree[right];
    }
//查询某段数组区间的和
    public static int query_tree(int arr[],int tree[],int node,int start, int end,int l,int r){
        if(r<start||l>end)
            return 0;
        else if(start>=l&&end<=r){
            return tree[node];
        }
        else if(start==end){
            return tree[node];
        }

        int mid=(start+end)/2;
        int left=2*node+1;
        int right=2*node+2;
        int left_sum=query_tree(arr,tree,left,start,mid,l,r);
        int right_sum=query_tree(arr,tree,right,mid+1,end,l,r);
        return left_sum+right_sum;
    }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河亦问安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值