【算法 & 高级数据结构】树状数组:一种高效的数据结构(一)

本文详细介绍了树状数组的概念,包括其在动态查询和频繁更新问题中的优势,涉及二进制索引和前缀和的基础知识。数学推导部分展示了如何通过二进制表示优化查询和更新操作,以及如何在修改元素后仅影响O(logn)个位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🚀个人主页为梦而生~ 关注我一起学习吧!
💡专栏算法题基础算法~赶紧来学算法吧
💡往期推荐
【算法基础 & 数学】快速幂求逆元(逆元、扩展欧几里得定理、小费马定理)
【算法基础】深搜



1 引言

1.1 树状数组的概念

树状数组(Binary Indexed Tree,BIT)是一种数据结构,用于高效地处理数组的动态查询和更新操作。它可以在O(log n)的时间复杂度内完成单点更新和前缀和查询操作。树状数组常用于解决数组频繁更新和查询前缀和的问题,比如求解逆序对、区间和等。

在这里插入图片描述

1.2 树状数组的应用场景

  1. 动态查询问题:树状数组非常适用于需要动态查询某个区间内元素和的场景。
  2. 频繁更新问题:树状数组也适用于频繁更新数组元素的情况。
  3. 逆序对问题:逆序对问题是一个常见问题,即找出数组中所有满足i<ja[i]>a[j](i, j)对。树状数组可以在O(nlogn)的时间复杂度内解决这个问题。

2 基础知识

2.1 二进制索引的概念和性质

二进制索引,也称为树状数组或有限差分数组,是一种特殊的数据结构,用于高效地处理数组中的前缀和查询。它的核心思想是利用二进制表示中的每一位来快速计算前缀和,从而实现高效的查询和更新操作。

在这里插入图片描述

概念

二进制索引的主要概念是基于数组元素的二进制表示来构建索引。具体来说,对于数组中的每个元素,我们可以将其下标转换为二进制形式,并根据二进制位来构建索引。通过维护这些索引,我们可以快速计算数组的前缀和,从而实现高效的查询和更新操作。

性质

  • 前缀和查询的高效性:二进制索引可以在O(log n)的时间复杂度内计算数组的前缀和。这是因为它利用了二进制表示的特性,通过跳跃式地计算不同位上的前缀和,实现了快速查询。
  • 单点更新的高效性:与前缀和查询一样,二进制索引也可以在O(log n)的时间复杂度内完成单点更新操作。当数组中的某个元素发生变化时,只需要更新对应的索引,即可快速反映到前缀和上。
  • 空间效率:二进制索引的空间复杂度与原始数组相同,即O(n)。它不需要额外的存储空间来维护索引结构,因此具有较高的空间效率。

2.2 前缀和的概念和计算

前缀和(Prefix Sum)是一个数组的概念,指的是数组中从第一个元素开始到某个位置元素(包括该位置元素)的总和。前缀和通常用于快速计算某个区间的和,避免了对每个元素进行逐一相加的操作,从而提高计算效率。

计算前缀和的方法很简单,通常是通过迭代数组中的每个元素,并将当前元素与前一个元素的前缀和相加,得到当前元素的前缀和。第一个元素的前缀和就是它本身。

例如,给定一个数组 arr = [1, 2, 3, 4, 5],它的前缀和数组 prefix_sum 可以这样计算:

prefix_sum[0] = arr[0] = 1  
prefix_sum[1] = arr[0] + arr[1] = 1 + 2 = 3  
prefix_sum[2] = arr[0] + arr[1] + arr[2] = 1 + 2 + 3 = 6  
prefix_sum[3] = arr[0] + arr[1] + arr[2] + arr[3] = 1 + 2 + 3 + 4 = 10  
prefix_sum[4] = arr[0] + arr[1] + arr[2] + arr[3] + arr[4] = 1 + 2 + 3 + 4 + 5 = 15

所以,前缀和数组 prefix_sum 为 [1, 3, 6, 10, 15]。


3 树状数组的定义和数学推导

3.1 通俗易懂的解释什么是树状数组※

在这里插入图片描述

对于一个数组,我们通常需要这样的操作:

  1. 修改某个元素的值
  2. 求一段区间的和

如果用朴素的做法,我们通常需要开一个数组,保存下来所有元素,每查询一次,遍历一次数组

但这会使得求和操作的时间复杂度达到 O ( n ) O(n) O(n),但如果数据量和查询次数达到上百万,这样的效率太低了

  • 但有人可能会想到,把数组中的元素两两求和,保存到另一个数组中:
    在这里插入图片描述

这样我们在计算的时候就会节省一半的时间,修改数据的时候也就是多改一个数字而已,但是对于很大的数据量,还是很慢。

  • 那我们可以再将这一层元素两两求和,往上叠加一层,直到只剩一个元素为止:
    在这里插入图片描述

这样即使要求和的数字很多,我们也可以利用这些额外的数组计算出需要的答案(用空间换时间的思想)

例如:要计算前14个数字的和
在这里插入图片描述
只需要计算这样4个数字就行
在这里插入图片描述

即使要计算前一百万个数字的和,我们也只需要进行10~20次加法

这样将查询的时间复杂度降到了 O ( log ⁡ n ) O(\log n) O(logn),效率提升了很多

观察这个数组我们可以发现,数组中的某些数字是不会用到的,大家可以手动模拟一下,所有层的第偶数个数字在计算时都不会被用到,都有更好的方案来替代
在这里插入图片描述

去除掉不会被用到的数字之后,剩下的数字正好是 n n n个,这与数组的长度是一样的

所以,我们可以用一个与原数组长度相同的数组来装下这些数,这个数组就是一颗树状数组,数组中的每一个元素都对应下面的每一个区间,这些区间表示的都是每个对应的区间和
在这里插入图片描述
求和时,我们只需要找到对应的区间,将这些区间相加即可找到答案

修改某个数据时,我们也只需要向上找到包含它的所有区间修改即可

所有查询以及修改元素的操作,都可以在 O

评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为梦而生~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值