线段树的创建插入查找删除

数据结构——线段树 线段树是一棵二叉树,其结点是一条“线段”——[a,b],它的左儿子和右儿子分别是这条线段的左半段和右半段,即[a, (a+b)/2 ]和[(a+b)/2 ,b]。线段树的叶子结点是长度为1的单位线段[a,a+1]。下图就是一棵根为[1,10]的线段树:易证一棵以[a,b]为根的线段树结点数是2*(b-a)-1。由于线段树是一棵平衡树,因此一棵以[a,b]为根结点的线段树的深度为log2(2*(b-a))。 阅读详情

一、线段树基本概念

           线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
    对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

    使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

   性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

二、线段树的存储数据结构

    由上面的图可以看出,存储一颗线段树和二叉树有点类似,需要左孩子和右孩子节点,另外,为了存储每条线段出现的次数,所以一般会加上计数的元素,其具体如下:

  1. struct Node         // 线段树  
  2. {  
  3.     int left;  
  4.     int right;  
  5.     int counter;  
  6. }segTree[4*BORDER];   
struct Node         // 线段树
{
	int left;
	int right;
	int counter;
}segTree[4*BORDER]; 

其中,;left代表 左端点、right代表右端点,counter代表每条线段出现的次数,BORDE代表线段端点坐标不超过100。由上面的性质可以知道,我们需要4倍的空间来存储。

三、线段树支持的操作

一颗线段树至少支持以下四个操作:

  • void construct(int index, int lef, int rig),构建线段树 根节点开始构建区间[lef,rig]的线段树
  • void insert(int index, int start, int end),插入线段[start,end]到线段树, 同时计数区间次数
  • int query(int index, int x),查询点x的出现次数,从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数
  • void delete_ (int c , int d, int index),从线段树中删除线段[c,d]

具体操作如下:

1、线段树的创建

  1. /* 构建线段树 根节点开始构建区间[lef,rig]的线段树*/  
  2. void construct(int index, int lef, int rig)  
  3. {  
  4.     segTree[index].left = lef;  
  5.     segTree[index].right = rig;  
  6.     if(lef == rig)   // 叶节点  
  7.     {  
  8.         segTree[index].counter = 0;  
  9.         return;  
  10.     }  
  11.     int mid = (lef+rig) >> 1;  
  12.     construct((index<<1)+1, lef, mid);  
  13.     construct((index<<1)+2, mid+1, rig);  
  14.     segTree[index].counter = 0;  
  15. }  
/* 构建线段树 根节点开始构建区间[lef,rig]的线段树*/
void construct(int index, int lef, int rig)
{
	segTree[index].left = lef;
	segTree[index].right = rig;
	if(lef == rig)   // 叶节点
	{
		segTree[index].counter = 0;
		return;
	}
	int mid = (lef+rig) >> 1;
	construct((index<<1)+1, lef, mid);
	construct((index<<1)+2, mid+1, rig);
	segTree[index].counter = 0;
}

2、线段树的元素插入

  1. /* 插入线段[start,end]到线段树, 同时计数区间次数 */  
  2. void insert(int index, int start, int end)  
  3. {  
  4.     if(segTree[index].left == start && segTree[index].right == end)  
  5.     {  
  6.         ++segTree[index].counter;  
  7.         return;  
  8.     }  
  9.     int mid = (segTree[index].left + segTree[index].right) >> 1;  
  10.     if(end <= mid)//左子树   
  11.     {  
  12.         insert((index<<1)+1, start, end);  
  13.     }else if(start > mid)//右子树   
  14.     {  
  15.         insert((index<<1)+2, start, end);  
  16.     }else//分开来了   
  17.     {  
  18.         insert((index<<1)+1, start, mid);  
  19.         insert((index<<1)+2, mid+1, end);  
  20.     }  
  21. }  
/* 插入线段[start,end]到线段树, 同时计数区间次数 */
void insert(int index, int start, int end)
{
	if(segTree[index].left == start && segTree[index].right == end)
	{
		++segTree[index].counter;
		return;
	}
	int mid = (segTree[index].left + segTree[index].right) >> 1;
	if(end <= mid)//左子树 
	{
		insert((index<<1)+1, start, end);
	}else if(start > mid)//右子树 
	{
		insert((index<<1)+2, start, end);
	}else//分开来了 
	{
		insert((index<<1)+1, start, mid);
		insert((index<<1)+2, mid+1, end);
	}
}

3、线段树的元素查找

  1. /* 查询点x的出现次数  
  2.  * 从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数 
  3.  */  
  4. int query(int index, int x)  
  5. {  
  6.     if(segTree[index].left == segTree[index].right) // 走到叶子,返回  
  7.     {  
  8.         return segTree[index].counter;  
  9.     }  
  10.     int mid = (segTree[index].left+segTree[index].right) >> 1;  
  11.     if(x <= mid)  
  12.     {  
  13.         return segTree[index].counter + query((index<<1)+1,x);  
  14.     }  
  15.     return segTree[index].counter + query((index<<1)+2,x);  
  16. }  
/* 查询点x的出现次数 
 * 从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数
 */
int query(int index, int x)
{
	if(segTree[index].left == segTree[index].right) // 走到叶子,返回
	{
		return segTree[index].counter;
	}
	int mid = (segTree[index].left+segTree[index].right) >> 1;
	if(x <= mid)
	{
		return segTree[index].counter + query((index<<1)+1,x);
	}
	return segTree[index].counter + query((index<<1)+2,x);
}

4、线段树的元素删除

  1. void  delete_ (int c , int  d, int index)  
  2. {  
  3.        if(c <= segTree[index].left && d >= segTree[index].right)   
  4.            segTree[index].counter--;  
  5.        else   
  6.        {  
  7.           if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left);  
  8.           if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right);  
  9.        }  
  10. }   

文章转载自:http://www.iteblog.com/archives/144

线段树 数据结构 数 统计 RMQ 线段树 数据结构 数 统计 RMQ 可以动态查询和添加 立即下载

相关推荐

dify离线部署

以bge-m3为例,本地部署bge-m3首先在一台能连网的linux服务器上(部署有ollama)创建想要保存模型的文件夹编辑ollama.service,配置ollama模型的保存路径添加模型存储地址将models目录设置属主,必须做,否则ollama无法启动重新加载配置文件并重启ollama测试ollama 运行是否正常最后拉取 bge-m3可在/opt/LLMModels/bge_m3/models目录下看到拉取得模型使用tar命令压缩文件夹。

weixin_42538734的博客 3069

数据结构:线段树

已迁往:http://www.wypblog.com/archives/144一、线段树基本概念 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区...

runfeel 456

数学之美 | 图论和网络爬虫

文章目录概述图论网络爬虫分析BFSDFSBFS + DFS参考资料 概述 这篇文章主要给大家介绍一下计算机算法中非常重要的一部分——图论,以及它在生活中的应用——网络爬虫。   图论 离散数学是当代数学的一个重要的分支,也是计算机科学的数学基础。它又包括四个分支,而图论便是其中一支,另外三个分别是:数理逻辑、集合论、近代数学。 图论中的图由一些节点和边构成,比如下面这张图 。 在图论中一个很基础...

小小酥梨的博客 3231

学习笔记——线段树

线段树 本文主要来自百度百科和这篇blog 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 长这样 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。 基本结构与建造 线段树是建立在线段的基础上,每个结点都代表了一条线段[a,b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线

No_wonder の 小站 523

【AI实战】用Coze工作流打造抖音视频文案提取神器——从单链接到批量处理的进阶指南

本文详细介绍了如何利用Coze工作流打造抖音视频文案提取工具,从单链接处理到批量提取的进阶指南。通过AI技术和工作流的结合,用户可以高效提取抖音视频的ASR和OCR文本,大幅提升内容创作效率。文章还涵盖了性能优化、异常处理及实际应用场景扩展,助力开发者快速实现抖音文案自动化提取。

weixin_29210759的博客 279

四足机器人跨楼层轨迹规划:SCAN-Planner-Pure-ROS2开源项目实践指南

在机器人导航领域,路径规划是让机器人从起点安全、高效移动到目标点的核心技术。其原理通常基于环境地图(如占据栅格地图或八叉树地图),通过搜索算法(如A*、RRT*)在配置空间中找到一条无碰撞的可行路径。这项技术的价值在于赋予机器人在复杂、非结构化环境中的自主移动能力,是巡检、救援、物流等应用场景的基石。对于四足机器人而言,其运动能力超越了轮式平台,能在楼梯、斜坡等三维地形中移动,这使得传统的二维规划不再适用,需要专门的三维轨迹规划算法。SCAN-Planner-Pure-ROS2正是这样一个专注于解决四足机器

weixin_30700977的博客 464

线段树(动态建点)

敌兵布阵

Jimmy_King 486

别再只会复制Haar级联代码了!OpenCV人脸检测全方案深度解析,从原理到工业级落地

通用预训练模型在你的业务场景效果不好时,用自己的业务数据集训练专属的级联器,是提升精度的终极方案,OpenCV自带和工具,支持自定义Haar/LBP级联器训练。场景首选方案次选方案新手入门学习Haar级联分类器LBP级联分类器嵌入式轻量固定场景LBP级联分类器YuNet轻量版工业级落地项目(99%场景)DNN+YuNetMTCNN多人脸+小目标复杂场景DNN+YuNet自定义微调模型同时做人脸+其他目标检测。

2601_94871597的博客 379

【原创】一维线段树的建树、插入、遍历和删除

一、定义: 线段树,说白了,就是把线段储存在一棵树里。 举一个例子: 数轴上,有一条线段[1,9]:12345678 将其二分:          12345678        1234    5678     12 34       56 78 1 2 3 4           5 6 7 8 这就是一棵线段树。 把数字换成线段,更清楚: 用严谨一点的语言,是一

致上 5354

备考路上的学习笔记:我的软考高级架构师复盘与更新计划

本专栏基于作者备考软考高级系统架构设计师的真实经验,分为考前突击、基础夯实、核心突破、案例实战和论文通关五大模块。内容涵盖计算机体系结构、操作系统、数据库等核心知识,提供案例解析和论文范文。作者承诺持续更新考纲内容、真题复盘及互动答疑,旨在帮助考生系统备考,将个人踩坑经验转化为实用指南,陪伴考生共同完成从知识碎片到体系构建的蜕变历程。

qq837993702的博客 2294

Nvidia Orin Driveos Camera 介绍及调试详解

自动驾驶-nvidia orin driveos Camera 驱动详解及调试

u011803281的博客 2992

区间树

区间树 注意:区间树和线段树不一样哦,线段树是一种特殊的区间树。 区间树: 区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点。通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成。相比于基础的红黑树数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值。逻辑结构如下所示:...

kexinxin1的博客 179

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

数据结构与算法----复习Part 15 (二叉搜索树与线段树)

二叉搜索树与线段树的图解,实现代码以及例题

半熟芝士的博客 1061

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

hdu 2852 KiKi's K-Number(线段树)

题目看起来很容易让人当成是划分树,但其实是个挺水的线段树。 0就是插入一个值,1就是删除一个值,如果树中不存在,就输出No Elment!2的话就是寻找树中从a开始往右查的第k个值。 因为值最大为100000,建树的时候以插入的值的范围建树。 #include #include #define N 100005 struct node { int x,y; int cnt;

zizaimengzhongyue的专栏 937

线段树

已迁往:http://www.wypblog.com/archives/144 一、线段树基本概念            线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。     对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉

liygcheng's coding world - 1095

区间树和线段树

注意:区间树和线段树不一样哦,线段树是一种特殊的区间树。 区间树: 区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点。通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成。相比于基础的红黑树数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值。逻辑结构如下所示:

1万+

洛谷P3835 【模板】可持久化平衡树(FHQ Treap)

题面 传送门 题解 可持久化一下就好了,具体可以看代码 这里有一个小\(trick\)就是我们原本在\(merge\)的时候也要新建节点的,但是我们\(merge\)之前一般已经\(split\)过了,需要的节点全都建起来了,所以不需要再新建了 //minamoto #include<bits/stdc++.h> #define R register #define inline __...

weixin_34306446的博客 198

线性表的创建,插入,查找,和删除的操作

#include using namespace std; const int MAX=50; typedef struct stu { int a[MAX]; int length; }sqlist; void intlist(sqlist &L); int chazhao(sqlist &L,int m); int shanchu(sqlist &L,int i); i...

weixin_44077170的博客 2052

数据结构:线段树 【转】

http://blog.youkuaiyun.com/wypblog/article/details/8219727 一、线段树基本概念 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]...

weixin_30652271的博客 131

笔试算法题(42):线段树(区间树,Interval Tree)

议题:线段树(Interval Tree) 分析: 线段树是一种二叉搜索树,将一个大区间划分成单元区间,每个单元区间对应一个叶子节点;内部节点对应部分区间,如对于一个内部节点[a, b]而言,其左子节点表示的区间为[a, (a+b)/2],其右子节点表示的区间为[1+(a+b)/2, b]; 对于区间长度为N的线段树,由于其单元节点都是[a, a]的叶子节点,所以其叶子节点数...

weixin_33748818的博客 557

c语言线段树建树程序,线段树的实现[C语言](原创)

线段树也是一种二叉树,只不过它的节点用来表示一个区间,其特征是将当前区间二分后分别作为左右孩子节点的区间,如下图(来自百度图片)所示:线段树在处理区间覆盖问题时,比较有用处,它支持的基本操作如下:1) 给定区间[i, j],创建一个线段树;【时间复杂度为O(j - i)】2) 将某个区间[i,j]插入到线段树中; 【时间复杂度为O(log(j-i))】3) 从线段树中删除某个区间[i,j]。...

weixin_29988907的博客 391
上一篇: 51单片机与PC进行串口通信
下一篇: MSP430 系统时钟 ACLK、MCLK、SMCLK
mib_du
博客等级 码龄14年 14粉丝 15原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值