iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >线段树详解以及C++实现代码
  • 215
分享到

线段树详解以及C++实现代码

2024-04-02 19:04:59 215人浏览 八月长安
摘要

目录应用场景算法思想查询操作修改操作算法实现建树查询修改总结应用场景 假设有这样的问题:有n个数,m次操作,操作分为:修改某一个数或者查询一段区间的值 分析下,如果针对数组元素的修改

应用场景

假设有这样的问题:有n个数,m次操作,操作分为:修改某一个数或者查询一段区间的值

分析下,如果针对数组元素的修改可以是O(1)完成,求某个区间值需要O(n)才可以完成,如果m和n都很大的情况,这个复杂度就很难接受了。

我们之前学过的前缀和算法可以解决区间求和的问题,并且时间复杂度是O(1),但如果涉及到修改操作,前缀和数组都需要重新计算,时间复杂度也是O(n)

有没有什么办法可以兼顾以上两种操作,并且可以将时间复杂度降低?

这就是我们要学习线段树!把修改和查询的时间复杂度都降到O(logn)!!!

算法思想

先来看下线段树长什么样:

有以下数组(为方便计算,数组下标从1开始)

我们把它转换成线段树,是长这样的:

1)叶子结点(绿色)存的都是原数组元素的值

2)每个父结点是它的两个子节点的值的和

3)每个父结点记录它表示区间的范围,如上图的“1-2”表示1到2的区间

下面我们来看看线段树是如何降低操作复杂度的!

查询操作

例如我们需要查询2-5区间的和

使用递归的思想:

2~5的和

=2~3的和+4~5的和

=3+5+4~5的和

=3+5+11

=19

总之,就是沿着线段树的划分把区间分开,再加到一块就行啦!

修改操作

例如,我们要把结点2的值由3->5,线段树需要沿着红色部分一个一个改,直到根结点:

不管是修改操作还是查询操作,时间复杂度都是O(logn)

下一步我们来看怎么实现线段树!

算法实现

首先我们需要将原始数组建立成一颗线段树,然后在树的基础上提供查询和修改的操作。

建树

观察上图,我们发现线段树是一棵近似完全二叉树,利用完全二叉树的性质,我们就可以直接用一个数组来存它。

就像上图一样把各个节点标上号,如果根节点编号是n,那它的左子树编号是2n,右子树的编号是2n+1

所以说,知道了根节点的编号,我们就可以快速有效的找到左右子树的根节点


void build(int root,int start,int end){
    if(start == end){
        tree[root] = num[start];
        return;
    }
    int leftroot = root * 2;//左结点
    int rightroot = root * 2 + 1;//右结点
    int mid = (start+end)/2;
    build(leftroot,start,mid);//递归计算左结点
    build(rightroot,mid+1,end);//递归计算右结点
    tree[root] = tree[leftroot] + tree[rightroot];//根结点值=左根+右根
}

查询


int query(int root,int start,int end,int l,int r){
    if(l<=start && r>= end){
        return tree[root];
    }
    int leftroot = root * 2;
    int rightroot = root * 2 + 1;
    int mid = (start+end)/2;
    int sum = 0;
    if(l<=mid){
        sum += query(leftroot,start,mid,l,r);
    }
    if(r>mid){
        sum += query(rightroot,mid+1,end,l,r);
    }
    return sum;
}

修改



void update(int root,int start,int end,int l,int r,int k){
    if(start == end){
        tree[root] += k;
        return;
    }
    int leftroot = root * 2;
    int rightroot = root * 2 + 1;
    int mid = (start+end)/2;
    if(l<=mid){
        update(leftroot,start,mid,l,r,k);
    }
    if(r>mid){
        update(rightroot,mid+1,end,l,r,k);
    }
    tree[root] = tree[leftroot] + tree[rightroot];
}

!!!:考虑下按区间修改元素值的复杂度?

注意事项:

1)我们在实现线段树时,实际存储肯定大于原始数组,我们一般让tree数组的长度为原始数据长度的3-4倍。

2)本文只是为了让大家学习线段树的实现原理,实际中我们可以将原始数组的start,end使用结构体存储,这样更简洁

总结

到此这篇关于线段树详解以及c++实现的文章就介绍到这了,更多相关C++实现线段树内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 线段树详解以及C++实现代码

本文链接: https://www.lsjlt.com/news/130712.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 线段树详解以及C++实现代码
    目录应用场景算法思想查询操作修改操作算法实现建树查询修改总结应用场景 假设有这样的问题:有n个数,m次操作,操作分为:修改某一个数或者查询一段区间的值 分析下,如果针对数组元素的修改...
    99+
    2024-04-02
  • C++ 线段树原理与实现示例详解
    目录一、问题引入二、线段树的构建三、线段树的单点修改与查询1、修改2、查询四、线段树的区间修改与查询1、修改2、查询一、问题引入 对于一般的区间问题,比如RMQ(区间的最值)、区间的...
    99+
    2024-04-02
  • C++怎么实现线段树
    本篇内容介绍了“C++怎么实现线段树”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录应用场景算法思想查询操作修改操作算法实现建树查询修改应...
    99+
    2023-06-20
  • 详解B+树的原理及实现Python代码
    B+树是自平衡树的高级形式,其中所有值都存在于叶级中。B+树所有叶子都处于同一水平,每个节点的子节点数量≥2。B+树与B树的区别是各节点在B树上不是相互连接,而在B+树上是相互连接的。 B+树多级索引结构图 B+树搜索规则 1、从...
    99+
    2024-01-24
    B树的概念
  • C语言详细讲解树状数组与线段树
    目录树状数组动态求连续区间和数星星线段树动态求连续区间和数列区间最大值树状数组 动态求连续区间和 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,...
    99+
    2024-04-02
  • C++实现二叉树及堆的示例代码
    1 树 树是一种非线性数据结构,它是由n个有限结点组成的具有层次关系的集合。把它叫树是因为它是根朝上,叶子朝下的 来上图瞧瞧 1.1 树的相关名词 2 二叉树 2.1 二叉树的...
    99+
    2024-04-02
  • C语言实现红黑树详细步骤+代码
    目录红黑树的概念红黑树的性质红黑树的定义与树结构插入新增结点插入后维护红黑树性质的主逻辑拆解讨论:旋转验证红黑树与AVl树的比较红黑树的应用总结红黑树的概念 红黑树,是一种二叉搜索树...
    99+
    2024-04-02
  • C++实现AVL树的完整代码
    AVL树的介绍 AVL树是一种自平衡的二叉搜索树,它通过单旋转(single rotate)和双旋转(double rotate)的方式实现了根节点的左子树与右子树的高度差不超过1...
    99+
    2024-04-02
  • C++模板以及实现vector实例详解
    目录函数模板类模板Vector实现简单的类模板实现代码及测试:win msvc编译器的实现:容器的空间配置器运算符重载与迭代器实现最终vector的实现代码总结函数模板 函数模板:是...
    99+
    2024-04-02
  • Linux中rm命令使用以及C/C++代码实现
    目录前言Linux rm 命令如何使用 rm 命令删除文件如何强制 rm 忽略不存在的文件如何在每次删除之前使 rm 提示如何使用 rm 命令删除目录如何让 rm 只删除空目录如何强...
    99+
    2024-04-02
  • C++线程池实现代码
    前言 这段时间看了《C++并发编程实战》的基础内容,想着利用最近学的知识自己实现一个简单的线程池。 什么是线程池 线程池(thread pool)是一种线程使用模式。线程过多或者频繁...
    99+
    2024-04-02
  • C语言超详细讲解栈的实现及代码
    目录前言栈的概念栈的结构栈的实现创建栈结构初始化栈销毁栈入栈出栈获取栈顶元素获取栈中有效元素个数检测栈是否为空总代码Stack.h 文件Stack.c 文件Test.c 文件前言 栈...
    99+
    2024-04-02
  • C++实现红黑树应用实例代码
    红黑树的应用: 1、利用key_value对,快速查找,O(logn) socket与客户端id之间,形成映射关系(socket, id) 内存分配管理 ...
    99+
    2024-04-02
  • Java数据结构之KMP算法详解以及代码实现
    目录暴力匹配算法(Brute-Force,BF)概念和原理next数组KMP匹配KMP全匹配总结我们此前学了前缀树Trie的实现原理以及Java代码的实现。Trie树很好,但是它只能...
    99+
    2022-12-08
    Java 数据结构 KMP算法 Java KMP算法 Java KMP
  • java 实现汉诺塔详解及实现代码
    java 实现汉诺塔详解及实现代码汉诺塔问题:有三根柱子A,B,C,其中A上面有n个圆盘,从上至下圆盘逐渐增大,每次只能移动一个圆盘,并且规定大的圆盘不能叠放在小的圆盘上面,现在想要把A上面的n个圆盘全部都移动到C上面,输出移动的总步数以及...
    99+
    2023-05-31
    java 汉诺塔 ava
  • C++代码实现链队列详解
    目录主要功能:完整代码展示:总结主要功能: 初始化、入队、出队、取队头元素、销毁队列、输出队列 完整代码展示: #include <iostream> using n...
    99+
    2024-04-02
  • C语言超详细讲解队列的实现及代码
    目录前言队列的概念队列的结构队列的应用场景队列的实现创建队列结构队列初始化  队列销毁  入队列  出队列  队列判空  获取队列元...
    99+
    2024-04-02
  • java 汉诺塔详解及实现代码
    java 汉诺塔详解及实现代码实现效果图打印的方法在 moveTheTopOne() 方法中被调用,调用该方法前打印出移动的方向--从X号塔往Y号塔汉诺塔要求:将第一座塔上的所有盘子,借助第二座塔,全部搬运到第三座塔上。规则:一次只能搬运一...
    99+
    2023-05-31
    汉诺塔 java ava
  • 纯C++代码详解二叉树相关操作
    目录前言 二叉树的概念二叉树的相关术语相关操作菜单二叉树的构造创建二叉树先序遍历二叉树  中序遍历二叉树后序遍历二叉树层次遍历二叉树二叉树的深度二叉树的叶子结点数...
    99+
    2024-04-02
  • 详解C++中vector的理解以及模拟实现
    目录vector介绍vector常见函数介绍vector模拟实现及迭代器失效讲解vector介绍 vector文档 1.vector是表示可变大小数组的序列容器。 2.就像数组一样,...
    99+
    2023-03-08
    C++ vector实现 C++ vector
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作