线段树-认识线段树+实现线段树

一、认识线段树

1、定义

线段树是平衡二叉树

2、特点

线段树将一个区间划分成单元区间,每个单元区间对应线段树中的一个结点

3、应用

频繁查找一个数组中指定区间内的和、最值

学了动态规划后使用迭代要好过使用递归,因为递归每次进去是有空间损耗的

二、线段树的实现(放数据、查数据)

1、线段树节点

/*线段树节点类*/
public class SegmentNode {public int start;// 区间起点public int end;// 区间终点public int sum;// 区间内求和public SegmentNode left;public SegmentNode right;public SegmentNode(int start, int end) {this.start = start;this.end = end;}
}

2、线段树的创建

/*线段树类*/
public class SegmentTree {private int[] elements;// 接收外界传入的数据public SegmentTree(int[] elements) {this.elements = elements;}public SegmentNode buildTree(int start,int end){if(start > end){return null;}SegmentNode newNode = new SegmentNode(start,end);if(start == end){newNode.sum = elements[start];return newNode;}// 当start < end时,由于线段树是节点区间整体取值,因此要进行递归,求取左右子树的值int mid = start + (end - start)/2;// 获取区间中点 不使用mid = (start + end)/2的原因是可能会超出int类型的最大值newNode.left = buildTree(start,mid);newNode.right = buildTree(mid + 1,end);newNode.sum = newNode.left.sum + newNode.right.sum;return newNode;}
}

3、打印线段树中的数据

(1)四种方式

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左中右

(2)前序遍历打印线段树中的数据

  • 核心代码
public void printTree(SegmentNode root,String prefix){System.out.println(prefix + "Node [" + root.start + "," + root.end + "] sum: " + root.sum);if(root.left != null){printTree(root.left, prefix+"  ");}if(root.right != null){printTree(root.right, prefix+ "  ");}}
  •  测试代码
public static void main(String[] args) {int[] nums = {1, 11, 5, 7, 9, 2};SegmentTree tree = new SegmentTree(nums);// 创建树SegmentNode root = tree.buildTree(0,nums.length-1);// 向树中放入数据tree.printTree(root, "");// 打印树}
  • 结果输出 

 

 4、在线段树中查询给定区间的和

(1)核心代码

public int query(SegmentNode root,int start,int end){// 所给区间与线段树区间无交集if(start > root.end || end < root.start){return 0;// 0: 作用1:代表所给区间与线段树无交集 作用2:不会影响给定区间求和}// 所给区间包含线段树区间if(start <= root.start && end >= root.end){return root.sum;// !!! 这一块要返回的是当前结点的和}// 所给区间与线段树区间有部分交集int leftSum = query(root.left,start,end);int rightSum = query(root.right,start,end);return leftSum + rightSum;}

(2)测试代码

public static void main(String[] args) {int[] nums = {1, 11, 5, 7, 9, 2};SegmentTree tree = new SegmentTree(nums);// 创建树SegmentNode root = tree.buildTree(0,nums.length-1);// 向树中放入数据tree.printTree(root, "");// 打印树System.out.println(tree.query(root,1,3));// 查询给定区间的和}

(3)结果输出

5、更新线段树中每个节点的sum属性的值(即给原来的每个数组元素的值都加上指定大小的更新新值

(1)优化代码的思想:要做一件事情的时候,先将这件事情攒着,当到达某一时间点的时候,把攒着的事情一块一做

(2)在线段树中,pushDown()方法用于实现懒更新策略。懒更新策略允许我们在更新操作时避免不必要的子树遍历,只在真正需要时将更新值下推到子节点,在节点中添lazy属性记录lazy值

(3)如果我们每进行一次加值的操作,就将全部线段树更改一遍,时间复杂度会很高,因此,我们需要进行一个延迟加和的操作

(4)具体思路:如果【left,right】区间增加a,在查询时,就可以把【left,right】区间标记的增加量推下去就可以直接求值了

(5)pushDown()方法

public void pushDown(SegmentNode node){// 子节点不存在不需要下推if(node.left == null || node.right == null){return;}if(node.lazy != 0){node.left.sum += node.lazy * (node.end - node.start + 1);node.left.lazy += node.lazy;node.right.sum += node.lazy * (node.end - node.start + 1);node.right.lazy += node.lazy;}node.lazy = 0;}

(6)update方法

缺点:不能将所有节点的sum属性的值全部正确更新

public SegmentNode update(SegmentNode root,int start,int end,int updateVal){// 给定区间与线段树区间无交集if(start > root.end || end < root.start){return null;// 给定区间有误,未进行更新操作}// 给定区间包含线段树区间if(start<=root.start && end>=root.end){root.sum += (root.end - root.start + 1)*updateVal;root.lazy += updateVal;return root;}pushDown(root);update(root.left,start,end,updateVal);update(root.right,start,end,updateVal);root.sum = root.left.sum + root.right.sum;return root;}

(7)测试代码

public static void main(String[] args) {int[] nums = {1, 3, 5, 7, 9, 11};SegmentTree tree = new SegmentTree(nums);// 创建树SegmentNode root = tree.buildTree(0,nums.length-1);// 向树中放入数据tree.printTree(root, "");// 打印树System.out.println("---------------------");tree.update(root,1,4,5);// 更新线段树,更新值为5tree.printTree(root, "");// 打印树}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146460.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

如何在qtcreator debugger上运行gdb命令

How to run gdb commands from qtcreator debugger? | Qt Forum gdb 调试基础操作和在qtcreator中使用gdb调试_qt gdb-CSDN博客 输出变量名&#xff1a; p变量名 ------------ gdb调试技巧&#xff08;二&#xff09;———— gdb 条件断点_gdb设置带函数入参判断的条件断点…

UE Asset Batch Duplication插件

目录 准备工作 "Scripting library" 三个最重要的功能&#xff08;前两个是UEditorUtilityLibrary中的&#xff09; 自动创建声明&#xff1a; TArray T 的含义 F 的含义 Live Coding &#xff08;Ctrlalt F11&#xff09; Live Coding 的工作流程&#xff…

时序预测|基于灰狼优化LightGBM的时间序列预测Matlab程序GWO-LightGBM 单变量和多变量 含基础模型

时序预测|基于灰狼优化LightGBM的时间序列预测Matlab程序GWO-LightGBM 单变量和多变量 含基础模型 文章目录 一、基本原理原理概述流程注意事项 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 时序预测中使用灰狼优化&#xff08;GWO&#xff09;结合LightGBM的…

Hash-通过哈希桶解决Hash冲突

哈希桶 基本结构 template<class T> struct HashNode {T _data;HashNode<T>* _next; }; template<class K,class T,class KeyOfT> class HashTable {typedef HashNode<T> Node; public:private:vector<Node*> _tables;size_t _num; }; insert …

《飞机大战游戏》实训项目(Java GUI实现)(设计模式)(简易)

目录 一、最终实现后&#xff0c;效果如下。 &#xff08;1&#xff09;简单介绍本游戏项目&#xff08;待完善&#xff09; &#xff08;2&#xff09;运行效果图&#xff08;具体大家自己可以试&#xff09; 初始运行情况。 手动更换背景图。 通过子弹攻击敌机&#xff0c;累…

java之单链表的基本概念及创建

1.链表的概念: 链表是一种 物理存储结构上非连续 存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。 组成结构: 由一系列节点组成&#xff0c;每个节点包含数据域和指向下一个节点的指针。 优点: 动态大小&#xff0c;易于插入和删除操作。 缺点…

无人机集群路径规划:​北方苍鹰优化算法(Northern Goshawk Optimization,NGO)​求解无人机集群路径规划,提供MATLAB代码

一、单个无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径&#xff0c;使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一&#xff0c;它可以通过算法和模型来确定无人机的航迹&#xff0c;以避开障碍物、优化…

51单片机——LED灯篇

一、LED与单片机P2管脚相连 二、点亮一个LED灯 #include <STC89C5xRC.H> void main() { P2 0xFE; //1111 1110 } P2有8个管脚&#xff0c;对应8个二进制位。 LED灯右侧接电源是正极&#xff08;1&#xff09;&#xff0c;左侧给负极&#xff08;0&#xff09;即可…

Web_php_include 攻防世界

<?php show_source(__FILE__); echo $_GET[hello]; $page$_GET[page]; while (strstr($page, "php://")) { 以是否检测到php://为判断执行循环$pagestr_replace("php://", "", $page);//传入空值&#xff0c;替换 } include($page); ?&g…

第四范式发布AIGS Builder企业级软件重构助手,以生成式AI重构企业软件

产品上新 Product Release 今天&#xff0c;第四范式发布企业级软件重构助手——AIGS Builder&#xff0c;可快速重构软件交互体验。传统的企业软件开发&#xff0c;每次迭代通常要以月计。基于第四范式AIGS Builder大模型&#xff0c;用生成式Agent替代复杂的界面&#xff0c;…

AI绘制调整虚线教程

1、打开ai的软件&#xff0c;执行菜单栏中的文件—新建&#xff0c;新建一个大小任意的画板&#xff0c;画板大小根据自己的需要来设置。 2、选择工具箱中的直线段工具&#xff0c;将填充设置为无&#xff0c;描边设置为黑色&#xff0c;描边大小稍微设置大一点&#xff0c;画一…

模拟实现STL的stack、queue、deque等的介绍

文章目录 前言一、模拟实现stack二、模拟实现queue三、 deque总结 前言 模拟实现STL的stack、queue、deque等的介绍 一、模拟实现stack STL的stack是通过增加一个容器的模板参数&#xff0c;不直接实现栈&#xff0c;让容器存储数据&#xff0c;并调用容器的接口实现栈 name…

环形链表问题——力扣141,142

环形链表问题——力扣141&#xff0c;142 141.判断链表是否带环142.给定一个链表&#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 NULL 141.判断链表是否带环 这道题不能用比较链表中的值来判断是否带环&#xff0c;因为链表中不同节点的值可以相同…

Java免税购物商城:Spring Boot技术实现

第二章 系统开发关键技术 2.1 JAVA技术 Java主要采用CORBA技术和安全模型&#xff0c;可以在互联网应用的数据保护。它还提供了对EJB&#xff08;Enterrise JavaBeans&#xff09;的全面支持&#xff0c;java servlet AI&#xff0c;JS&#xff08;java server ages&#xff09…

matlab绘制二维云图,划分区域,并显示每个区域的均值

绘制成图如下&#xff1a; 代码如下&#xff1a; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%创建绘图的数据 ax0;bx1; ay0;by1; nx100; %数据的x轴点数 ny100; %数据的y轴点数 hx(bx-ax)/(nx-1); hy(by-ay)/(ny-1); Xax:hx:bx; Yay:hy:by; da…

有趣的Python-turtle

1 介绍 turtle 是 Python 中用来绘图的标准库&#xff08;Python解释器在安装后import直接使用&#xff09;&#xff0c;它简单且有趣&#xff0c;作为 Python初学者 都可以将它作为第一个学习对象&#xff0c;培养程序学习的兴趣&#xff0c;建立编程带来的成就感&#xff0c…

网络安全-webshell绕过,hash碰撞,webshell绕过原理

目录 一、题目 1.1 1.2 1.3 1.4 1.5 二、绕过动态检测引擎的一次尝试 三、一个比赛中的webshell 四、webshell绕过的原理以及哈希碰撞 五、JSP解释流程导致的绕过&#xff08;QT比赛&#xff09; 5.1环境 5.2例子 一、题目 这里我们通过几道题目来给大家讲解 1.…

Springboot3 + MyBatis-Plus + MySql + Uniapp 实现商品规格选择sku(附带自设计数据库,最新保姆级教程)

Springboot3 MyBatis-Plus MySql Uniapp 实现商品规格选择sku&#xff08;附带自设计数据库&#xff0c;最新保姆级教程&#xff09; 1、效果展示2、数据库设计2.1 商品表2.2 商品价格和规格中间表2.3 商品规格表 3、后端代码3.1 model3.2 vo3.3 mapper、server、serverImp3…

前端-javaScript:jquery补充

jquery绑定事件的方式 1.直接使用事件函数 &("div").click(function(){alert(1)}) 2.用统一的on函数绑定事件 on(事件类型&#xff0c;事件函数) $("div").on("click",function(){alert(2)}) 事件类型以参数的类型传递 --->可以同时绑…

go webapi上传文件 部属到linux

go厉害的地方&#xff0c;linux服务器上无需安装任务依赖就可以运行&#xff0c;大赞&#xff01; 一、编译 #在Goland中cmd中执行 go env -w GOARCHamd64 go env -w GOOSlinux go build main.go # 切换回来 否则无法运行 go env -w GOOSwindows go run main.go 拷贝到linux服…