【数据结构与算法】树状数组

2023-10-27

Fenwick Tree


树状数组(Binary Indexed Tree,又称 Fenwick Tree)是一种基于数组实现的数据结构,用于高效地动态维护前缀和。

树状数组可以在 O ( log ⁡ n ) O(\log n) O(logn) 的时间复杂度内进行单点修改前缀求和操作,适用于一些仅需要维护前缀和的问题,例如区间求和、区间平均数、区间中位数等。

一、问题描述

对于给定数组 a 1 , a 2 , . . . , a [ n ] a_{1},a_{2},...,a[n] a1,a2,...,a[n],当需要频繁询问某一区间 a i , a i + 1 , . . . , a [ j ] a_{i},a_{i+1},...,a[j] ai,ai+1,...,a[j] (其中 1 < = i < j < = n 1<=i<j<=n 1<=i<j<=n),且存在修改 a i a_{i} ai 元素值的情况时,如何设计一种高效的查询和修改算法?

一种直观的做法是暴力法,即每次使用 O ( 1 ) O(1) O(1) 的时间复杂度进行单点修改,但是查询的过程中由于需要遍历区间中的每个元素,最坏情况需要 O ( n 2 ) O(n^{2}) O(n2) 的时间(这里是假设操作的规模是 O ( n ) O(n) O(n) )。为了解决这种查询效率低下的情况,一种思路是使用树状数组。

二、解决思想

在树状数组 d d d 中,每个数组位置所存储的值并不仅仅是当前元素的值,而是一定区间内元素的累加值,具体存储规则如下图左图示所示。

在这里插入图片描述

左图示中,元素下标对应的矩阵表示该位置存储的值为矩阵覆盖区域对应的原数组元素之和,比如下标为 1 1 1 处存储原数组下标为1的元素值,下标为4处存储原数组下标为 1 1 1 4 4 4 的元素值之和。

树状数组的存储图中反映的存储规律为:

编号为 x x x 的节点所管辖的区间为 2 k 2^{k} 2k(其中 k k k x x x 二进制末尾 0 的个数)个元素。

比如 d [ 6 ] = a [ 5 ] + a [ 6 ] d[6] = a[5] + a[6] d[6]=a[5]+a[6],因为位置 6 对应的二进制为 110,末尾的 0 个数为 1,因此需要存储 2 1 = 2 2^{1} = 2 21=2 个元素,其他同理。

有了上述的存储规则后,如何进行区间查询和元素修改操作呢?为了便于对操作的描述,可将左侧图示进行旋转获得右侧图示(树的深度为 l o g 2 n + 1 log_{2}{n+1} log2n+1),并用直线连接表示前缀累加节点之间的关联关系。另外,为了便于后续对区间查询和元素修改操作的描述,这里引入 lowbit 操作:

public int lowbit(int x) {
    return x & (-x);
}

即所谓的 lowbit 操作就是为了获取当前变量 x x x 二进制中最后一个 1 的位置。这个操作可以先记住,后续的操作介绍中能帮助进一步理解。

(1)区间查询

在右侧图示的树结构中,若查询某个节点的前缀和,则需要从这个点向左上找到上一个节点,并加上其节点的值,以此不断向左上查找节点值并累加。比如,查询 节点 7 的前缀和,需要从 节点7 出发, 找到 节点 6 进行累加操作,再找到 节点 4 进行累加操作(可以结合图中矩阵的覆盖面积进行理解)。那么这一遍历过程是如何实现的呢?这需要我们先将节点编号转成二进制的形式:

  • 7 ---- 0111
  • 6 ---- 0110
  • 4 ---- 0100

可以发现一个普遍的规律:下一次遍历的位置 x ′ x' x 是当前位置 x x x 在二进制位上抹去最后一个 1 1 1。因此,这时就可以使用到我们之前提到的 lowbit 操作了,即对于下一次遍历的位置 x ′ x' x 有: x ′ = x − l o w b i t ( x ) x' = x - lowbit(x) x=xlowbit(x)

(2)元素修改

元素修改可以看作是区间查询的逆过程,即在右侧图示的树结构中,若修改其中的某一节点,则需要一层一层向上找到父节点(向右上方,与区间查询正好相反),并按照需要对每个父节点进行相同的修改处理。比如,对 节点 3 进行加 k k k 操作,则需要依次遍历 节点 3节点 4节点 8 并在遍历的过程中进行加 k k k 操作。在遍历下一个节点的过程中,只需要使用与区间查询类似的逆向过程即可,即对当前 x x x 位置节点,下一遍历节点 x ′ = x + l o w b i t ( x ) x' = x+lowbit(x) x=x+lowbit(x)

三、代码实现

class FenwickTree {
    private int[] tree;
    
    public FenwickTree(int n) {
        tree = new int[n+1];
    }
    
    public int lowbit(int x) {
        return x & (-x);
    }
    
    public void add(int i, int val) {
        while(i < tree.length) {
            tree[i] += val;
            i += lowbit(i);
        }
    }
    
    public int query(int i) {
        int res = 0;
        while(i > 0) {
            res += tree[i];
            i -= lowbit(i);
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【数据结构与算法】树状数组 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 如何从终端运行处理应用程序

    我目前正在使用加工 http processing org对于一个小项目 但是我不喜欢它附带的文本编辑器 我使用 vim 编写所有代码 我找到了 pde 文件的位置 并且我一直在从 vim 中编辑它们 然后重新打开它们并运行它们 重新加载脚
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will

随机推荐

  • 蓝桥杯JAVA B组 2020(2)第三题 合并检测

    一 题目描述 如果结果为阴性 则说明这 k个人都是阴性 用一个试剂盒完成了 k 个人的检测 如果结果为阳性 则说明至少有一个人为阳性 需要将这 k 个人的样本全部重新独立检测 加上最开始的合并检测 一共使用了 k 1 个试剂盒完成了 k 个
  • 基于ssm框架的毕业设计管理系统 毕业设计-附源码211633

    摘 要 随着科学技术的飞速发展 各行各业都在努力与现代先进技术接轨 通过科技手段提高自身的优势 对于毕业设计管理系统当然也不能排除在外 随着网络技术的不断成熟 带动了毕业设计管理系统 它彻底改变了过去传统的管理方式 不仅使服务管理难度变低了
  • VMware出现“该虚拟机似乎正在使用中”问题

    按照以下步骤解决虚拟机异常关机无法打开问题 1 在用VMware虚拟机的时候 有时会发现打开虚拟机时提示 该虚拟机似乎正在使用中 如果该虚拟机未在使用 请按 获取所有权 T 按钮获取它的所有权 否则 请按 取消 按钮以防损坏 配置文件 D
  • Android——使用DatePicker和TimePicker显示当前日期和时间

    1 DatePicker和TimePicker两种实现动态输入日期和时间的功能 2 DatePickerDialog和TimePickerDialog两种实现动态输入日期和时间的对话框 3 两组监测日期和时间改变的监听器 1 OnDateC
  • vue中使用百度地图 添加标记物,点击标记物弹窗,画运动轨迹,位置纠偏,逆地址解析

    在vue项目中使用百度地图 添加标记物 位置纠偏 信息弹窗 画轨迹 坐标转换 逆地址解析 参考vue baidu map开发文档 安装 npm install vue baidu map save 全局注册 在main js中引入以下代码
  • 【Vue】关于开发中本地图片加载失败的经验总结

    文章目录 1 图片存放在assets 2 图片存放在static中 3 其他需要注意的点 我的源码 img或者el avatar中的src没有提供静态值 而是绑定一个动态变量 如果这个变量的路径是存放在assets里 则图片会加载失败 1
  • nginx代理路径配置总结

    一 发现问题 配置nginx代理的时候 发现location配置的路径和代理的上下文路径的组合不同 服务端接收到的uri的路径不同 导致了controller的RequestMapping匹配出现问题 所以就仔细研究了一下nginx路径配置
  • 对象属性拷贝(BeanUtils.copyProperties)用法

    系列文章目 对象属性拷贝 BeanUtils copyProperties 用法 一 BeanUtils copyProperties参数赋值顺序 根据导包不同 方式不同 一个为org springframework beans BeanU
  • MySQL数据库渗透及漏洞利用总结

    Mysql数据库是目前世界上使用最为广泛的数据库之一 很多著名公司和站点都使用Mysql作为其数据库支撑 目前很多架构都以Mysql作为数据库管理系统 例如LAMP 和WAMP等 在针对网站渗透中 很多都是跟Mysql数据库有关 各种Mys
  • FCKEditor 2.3.2 的type漏洞修复

    从网上下了最新的FCKeditor 2 3 2和对应的JSP整合文件FCKeditor 2 3 安装后进行测试 发现type漏洞仍然存在 汗 漏洞情况是 或在type后面跟上一个非file image flash media参数 就可以上传
  • 探索数据分析与可视化:使用R语言实现

    探索数据分析与可视化 使用R语言实现 概述 数据分析与可视化是现代数据科学中至关重要的环节 R语言作为一种强大的统计分析工具和编程语言 提供了丰富的功能和库来处理数据 进行统计分析和生成可视化图表 本文将介绍如何使用R语言进行数据分析与可视
  • 关于 cocos2d-x win32 版本的 cpu 占用改良

    初学 c2dx 下载的 2 02 版本 发现其 HelloWorld 演示项目 居然一直占据了 100 的 CPU 猜测它有可能是在主循环里使用了 Sleep 0 一搜 果然定位到具体代码 它位于 cocos2dx platform win
  • Flutter常用布局方式

    文章目录 flutter 布局介绍 一 Container 布局 1 属性 2 示例 二 线性布局 1 说明 2 属性 3 示例 三 弹性布局 Flex 1 属性 2 Expanded 的使用 3 示例 四 流式布局 1 说明 2 属性 3
  • 方差、标准差、平方差、残差

    2018 06 21 创建人 Ruo Xiao 邮箱 xclsoftware 163 com 2018 06 29 修改人 Ruo Xiao 增加对残差的说明 一 方差 1 定义 数据分别与其平均数的差的平方和的平均数 由 D 表示 2 意
  • Nssm 安装Window服务

    环境 Wind10 1 下载nssm exe 官网 http nssm cc download 2 解压 根据操作系统选择32位或64位nssm 在该目录启动命令行窗口 3 服务注册 命令行输入 nssm exe install XX或者n
  • 在CentOS7上安装RabbitMQ(RPM安装方式)

    首先需要安装erlang 参考 http fedoraproject org wiki EPEL FAQ howtouse rpm Uvh https download fedoraproject org pub epel epel rel
  • SQL命令笔记

    sql中的排序倒序 排序采用 order by 子句 order by 后面跟上排序字段 排序字段可以放多个 多个采用逗号间隔 order by默认采用升序 asc 如果存在 where 子句 那么 order by 必须放到where 语
  • 使用VS配置OCCI环境

    一 配置方法 1 准备好occi的两个配置文件sdk与basic 之后将VS内的设置环境为release x64 2 c c 常规 附加库包含目录 F programmsoftware occi instantclient sdk wind
  • IDEA插件之 时序图 -- Sequence Diagram

    安装插件 使用 在方法上右击选择 Sequence Diagram 设置参数 可在控制台内查看时序图结果
  • 【数据结构与算法】树状数组

    Fenwick Tree 树状数组 Binary Indexed Tree 又称 Fenwick Tree 是一种基于数组实现的数据结构 用于高效地动态维护前缀和 树状数组可以在 O log n