当前位置: 首页 > article >正文

基于完全二叉树实现线段树-- [爆竹声中一岁除,线段树下苦踌躇]

在这里插入图片描述

文章目录

  • 一.完全二叉树
    • 完全二叉树的父子结点引索关系
  • 二.线段树
  • 三.基于完全二叉树实现线段树
    • 关于线段树的结点数量问题的证明
    • 递归建树
    • 递归查询区间和
    • 递归单点修改
    • 线段树模板题

一.完全二叉树

  • 完全二叉树的物理结构是线性表,逻辑结构是二叉树
    在这里插入图片描述

完全二叉树的父子结点引索关系

  • 通过子结点下标引索父结点下标 : 父结点下标 = 子节点下标/2;
  • 通过父结点下标引索左孩子下标 : 左孩子下标 = 父结点下标 * 2;
  • 通过父结点下标引索右孩子下标 : 右孩子下标 = (父结点下标 * 2) + 1;
    在这里插入图片描述

二.线段树

  • 线段树是一种基于分治思想实现的数据结构,用途非常广泛,常用于快速引索动态更新数组的区间和,以及解决众多类型的区间问题
  • 现有一个原数组,线段树结点表示一个结构体,结构体中存储原数组某一段区间的端点下标区间和
struct TreeNode{
	int left;   //原数组区间左端点下标
	int right;  //原数组区间右端点下标
	int Sum;    //区间和
}
  • 线段树根节点存储整个原数组的区间和,然后以区间二分的方式构建左子结点和右子结点:
    在这里插入图片描述
  • 以此类推,形成递归,直到将原数组区间划分为一个个单元素区间为止:
    在这里插入图片描述
  • 建树过程时间复杂度为O(N),引索更新的复杂度都是logN,比如要引索原数组[1,4]的区间和:
    在这里插入图片描述

三.基于完全二叉树实现线段树

在这里插入图片描述

关于线段树的结点数量问题的证明

  • 证明:若根节点的区间长度为N,线段树的总结点数量不会超过4*N
    在这里插入图片描述
  • 使用线段数时,数据范围为N,则定义一个4*N大小的完全二叉树数组防止算法中出现数组越界问题

递归建树

  • int BuildTree(TreeNode * Tree,int index,int left,int right)
    • 调用BuildTree(Tree,1,left,right)从下标1(根节点)开始递归建立线段树,[left,right]表示原数组的区间
    • 返回值表示原数组[left,right]的区间和
void Bulid(TreeNode* Tree,int index , int left , int right){
    //结点赋值
    Tree[index] = {left,right,0};
    if(right == left)return;
    //二分区间
    int mid = ((right - left) >> 1) + left;
    //构建左子树
    Bulid(Tree,index << 1,left, mid);
    //构建右子树
    Bulid(Tree,(index << 1)|1, mid + 1 , right);
}
  • 递归建树的时间复杂度为O(N)

递归查询区间和

  • int Get_Sum(TreeNode* Tree,int index , int left , int right)表示查询原数组[left,right]的区间和
//查询区间和
int Get_Sum(TreeNode* Tree,int index , int left , int right){
    //当前区间被目标区间包含则返回区间部分和
    if(Tree[index].left >= left && Tree[index].right <= right){
        return Tree[index].Sum;
    }
    //二分查询左右子树
    int mid = (Tree[index].left + Tree[index].right) >> 1;
    int res = 0;
    if(mid >= left) res = Get_Sum(Tree,index << 1,left,right);
    if(mid < right) res += Get_Sum(Tree,index << 1 | 1 , left , right);
    return res;
}
  • 关于复杂度的分析:
    在这里插入图片描述

递归单点修改

  • void modify(TreeNode* Tree,int index,int target,int change),原数组下标为target的元素加上change,调用时index1(根节点下标)开始递归
//原数组下标为target的元素加上change
void modify(TreeNode* Tree,int index,int target,int change){
    Tree[index].Sum += change;
    if(Tree[index].left  == Tree[index].right)return;
    //二分被修改区间
    int mid = (Tree[index].left + Tree[index].right) >> 1;
    if(target <= mid) modify(Tree,index << 1,target,change);  //递归修改左子树
    else modify(Tree,index << 1 | 1 , target,change);         //递归修改右子树
}

线段树模板题

线段树模板题1
线段树模板题2

在这里插入图片描述


http://www.kler.cn/a/233644.html

相关文章:

  • 深入理解接口测试:实用指南与最佳实践5.0(一)
  • 使用pytest+openpyxl做接口自动化遇到的问题
  • 6.2 对角化矩阵(2)
  • 修改yolo格式的labels类别、删除yolo格式的labels类别
  • LLM - 使用 LLaMA-Factory 微调大模型 Qwen2-VL SFT(LoRA) 图像数据集 教程 (2)
  • 【webrtc】 RTP 中的 MID(Media Stream Identifier)
  • 风行智能电视G32Y 强制刷机升级方法,附刷机升级数据MstarUpgrade.bin
  • 【Java八股面试系列】并发编程-并发关键字,线程池
  • Leetcode 337 打家劫舍 III
  • 软件测试学习笔记-使用jmeter进行性能测试
  • ChatGPT高效提问—prompt常见用法(续篇四)
  • Acwing831KMP字符串
  • 【极数系列】Flink集成KafkaSink 实时输出数据(11)
  • 神经网络 | CNN 与 RNN——深度学习主力军
  • Redis篇之过期淘汰策略
  • springboot微信小程序 uniapp学习资料分享系统v9uy4
  • 【大厂AI课学习笔记】【1.5 AI技术领域】(8)文本分类
  • containerd中文翻译系列(二十一)用户命名空间
  • 一次显著的性能提升,从8s到0.7s
  • ClickHouse--02--安装
  • C++进阶(十三)异常
  • JAVA设计模式之代理模式详解
  • IDEA中Git的使用小技巧-Toolbar(工具栏)的设置
  • JVM 性能调优 - 常用的垃圾回收器(6)
  • MyBatisPlus之分页查询及Service接口运用
  • 【docker常见命令】