线段树初步理解

线段树定义:

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
[1]

对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

主要遇到的问题:
要解决计算某一数组任意区间长度,并且在随机改变一个值后,在计算这个区间和
运用线段树可以降低时间复杂度。

主要涉及三个函数
1.根据所给数组,创建一个线段树(满二叉树,不够补0)
2.改变一个值,更新线段树
3.计算L-R的区间和

下面为程序代码:

//线段树
//主要解决问题,在一串数组中计算随机长度的的和,并随机改变任意的值,再算其长度
#include<stdio.h>
#define MAX_LEN 1000

void build_tree(int arr[],int tree[],int node,int start,int end)
{
     if(start==end)  //node是把树展开,对应的下标的值 
          {
               tree[node]=arr[start];
          }
      else
           {
               int mid=(start+end)/2;
               int left_node=2*node+1; //左子树 
               int right_node=2*node+2; //右子树 
               build_tree(arr,tree,left_node,start,mid);
               build_tree(arr,tree,right_node,mid+1,end);
               tree[node]=tree[left_node]+tree[right_node];  
           }
} 

void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val)//idx:待改变的数组下标,val:改成的值
 //这条路上的根节点都需要更新 
{
      if(start==end)
       {
           arr[idx]=val;
           tree[node]=val;
        } 
       else
         {
            int mid=(start+end)/2;
            int left_node=2*node+1; //左子树 
            int right_node=2*node+2; //右子树 
            if(idx>=start&&idx<=mid)  //在左子树
              {
                   update_tree(arr,tree,left_node,start,mid,idx,val);
               } 
             else
               {
                   update_tree(arr,tree,right_node,mid+1,end,idx,val);
               }
              tree[node]=tree[left_node]+tree[right_node]; 
            }
} 

int query_tree(int arr[],int tree[],int node,int start,int end,int L,int R) //求arr[]L到R的和
{
     printf(" start = %d\n",start);
     printf(" end   = %d\n",end);
     printf("\n");
     if(R<start||L>end)  //不在范围内 
        {
           return 0;
        } 
      else if(start>=L&&end<=R) //start end 完全在L R范围内,不需要向下递归 
        {
           return tree[node];
        } 
       else if(start==end)
         {
            return tree[node];
         } 
       else
         {
            int mid=(start+end)/2;
            int left_node=2*node+1; //左子树 
            int right_node=2*node+2; //右子树 
            int sum_left=query_tree(arr,tree,left_node,start,mid,L,R);
            int sum_right=query_tree(arr,tree,right_node,mid+1,end,L,R);
            return sum_left+sum_right;
          }
} 

int main()
{
      int arr[]={1,3,5,7,9,11};
      int size=6;
      int tree[MAX_LEN]={0};
      build_tree(arr,tree,0,0,size-1);
      for(int i=0;i<15;i++)  //15是根据二叉树算出来的 
        {
              printf("%d ",tree[i]);
        }
       printf("\n");
       update_tree(arr,tree,0,0,size-1,1,4); //将3换成4
       for(int i=0;i<15;i++)  //15是根据二叉树算出来的 
         {
             printf("%d ", tree[i]);
          }
        printf("\n");
        int sum=query_tree(arr,tree,0,0,size-1,0,4);
        printf("%d",sum);
        return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值