线段树的创建插入查找删除
一、线段树基本概念
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[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],线段树需要的空间为数组大小的四倍
二、线段树的存储数据结构
由上面的图可以看出,存储一颗线段树和二叉树有点类似,需要左孩子和右孩子节点,另外,为了存储每条线段出现的次数,所以一般会加上计数的元素,其具体如下:
- struct Node // 线段树
- {
- int left;
- int right;
- int counter;
- }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、线段树的创建
- /* 构建线段树 根节点开始构建区间[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;
- }
/* 构建线段树 根节点开始构建区间[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、线段树的元素插入
- /* 插入线段[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);
- }
- }
/* 插入线段[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、线段树的元素查找
- /* 查询点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);
- }
/* 查询点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、线段树的元素删除
- void delete_ (int c , int d, int index)
- {
- if(c <= segTree[index].left && d >= segTree[index].right)
- segTree[index].counter--;
- else
- {
- if(c < (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].left);
- if(d > (segTree[index].left + segTree[index].right)/2 ) delete_( c,d, segTree[index].right);
- }
- }
文章转载自:http://www.iteblog.com/archives/144
线段树的创建插入查找删除相关推荐
- c语言 trie树,C语言实现Trie树(字典树)的插入查找删除与遍历操作
Trie树,也称作是字典树,是一种哈希树的变种,查询效率较高.Trie树可以用于统计或者排序大量的字符串,比如对一系列字符串按照字典序排序. 字典树是一个多叉树,每一个节点上存储的不是一个字符串,而是 ...
- 线段树线段树的创建线段树的查询单节点更新区间更新
目录 线段树 什么是线段树? 线段树的创建 线段树的查询 单节点更新 区间更新 未完待续 线段树 实现问题:常用于求数组区间最小值 时间复杂度:(1).建树复杂度:nlogn.(2).线段树算法复杂度 ...
- hdu4267线段树段更新,点查找,55棵线段树.
题意: 给你N个数,q组操作,操作有两种,查询和改变,查询就是查询当前的这个数上有多少,更改是给你a b k c,每次从a到b,每隔k的数更改一次,之间的数不更改,就相当于跳着更新. 思路: ...
- 字典树简单实现 插入 查找 遍历
字典树是一种存储字符串的高效的结构,它保存了不同字符的相同前缀,又因此叫做前缀树,使用前缀,大大避免相同字符的重复匹配,加快查找效率 字典树是一颗多叉树,比如存储26个字母的,那么就有26叉 字典树的 ...
- 洛谷 P3368 【模板】树状数组 2(线段树区间加单点查找)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个 ...
- Codeforces Round #413 C. Fountains (线段树的创建、查询、更新)
vj题目链接: https://vjudge.net/contest/235444#problem/F 题意: 有 n 个待建的喷泉,每个的建造代价为pi coins或者pi diamonds(co ...
- 线段树——操作格子(蓝桥杯试题集)
题目链接: http://lx.lanqiao.cn/problem.page?gpid=T18 题目描述: 有n个格子,从左到右放成一排,编号为1-n. 共有m次操作,有3种操作类型: 1.修改一个 ...
- 【算法微解读】浅谈线段树
浅谈线段树 (来自TRTTG大佬的供图) 线段树个人理解和运用时,认为这个是一个比较实用的优化算法. 这个东西和区间树有点相似,是一棵二叉搜索树,也就是查找节点和节点所带值的一种算法. 使用线段树可以 ...
- CodeForces - 1417F Graph and Queries(克鲁斯卡尔重构树的dfs序上建线段树)
题目链接:点击查看 题目大意:给出一个 n 个点 m 条边组成的无向图,每个点初始时都有一个权值 val,满足: 每个点的 val[ i ] 各不相同 val[ i ] ∈ [ 1 , n ] 现在有 ...
最新文章
- 赫夫曼编码(基于赫夫曼树的实现)
- GraphNVP | 用于分子图生成的可逆流模型
- Android中的ImageView的getDrawableCache获取背景图片的时候注意的问题
- JavaScript(十三)面向对象
- Chrome Native Client 原理
- 使用PostgREST构建PostgreSQL数据库的REST风格API
- Android学习点点滴滴之获取正在运行的进程
- wxPython多个窗口的基本结构
- App Store审核宝典
- mysql主从配置查看_MySQL主从配置 - MySQL入门教程_数据库技术_Linux公社-Linux系统门户网站...
- matlab伏安特性曲线的图,电源伏安特性曲线的意义详细解析
- jitsi各工程编译笔记(一)各工程大概
- 服务器装win7没有硬盘分区,深度win7安装没有磁盘分区怎么办?
- Scratch中做一个简单迷宫小游戏,值得您收藏!
- C语言atoi、atol、atoll和atoq函数
- DEDECMS站点内容怎么自动更新到新浪微博
- CentOS7中文输入法,拼音输入法
- 恒压板框过滤实验数据处理_鞍山高温除尘袋公司,板框压滤机滤布,热门_泰翔工业滤料...
- No view found for id 0x7f05003c (*) for fragment PlaceholderFragment
- 装饰模式实例与解析 实例一:变形金刚
热门文章
- vue 数组删除(对象)单条删除,多条删除
- 视频直播取代微博不是天方夜谭
- python中显示图片和文字
- TInkPadT490s+单硬盘 Ubutun+Win10双系统安装问题总结
- Unity——在运行时修改Animator Controller状态机中的动画片段
- vmware下Ubuntu挂载U盘
- openGauss单机版升级示例(2.0.1—>3.1.1)
- 秀米编辑器(xiumi)+百度编辑器(Ueditor) 集成 :解决集成问题,秀米编辑器导出到百度编辑器格式问题,图片保存到自己的服务器(阿里云OSS)
- 高考400分计算机专业,高考400分 计算机专业
- python 将图片转换成像素画_Python用61行代码实现图片像素化