当前位置: 首页 > news >正文

二叉树算法之 Fenwick 树(Binary Indexed Tree, BIT)详细解读

Fenwick 树,也称为 树状数组二进制索引树(Binary Indexed Tree, BIT),是一种用于处理动态数组前缀和查询和修改的数据结构。它提供了一种高效的方法来在动态数据中求解区间和问题,并支持单点更新和区间查询操作。

Fenwick 树的优势在于它能够以 O(log n) 的时间复杂度进行区间查询和更新操作,适用于场景包括动态维护数组前缀和、逆序对计算等问题。

1. Fenwick 树的基本概念

Fenwick 树维护一个数组,通过二进制的方式对前缀和进行分块存储。其核心思想是利用数组的下标和二进制表示的性质,将数组划分为若干区间,每个区间的大小为2的某个次方。

Fenwick 树的基本操作:
  1. 单点更新:将数组的某个元素增加一个值。
  2. 前缀和查询:求数组从起点到某个位置的区间和。

通过这些操作,可以高效地处理数据的动态更新和快速查询。

2. Fenwick 树的存储结构

Fenwick 树使用一个数组 BIT[] 来存储数据,每个位置 i 存储的是一个子数组的和。对于每个下标 i,可以通过最低位为1的二进制位来确定该位置所代表的区间长度。例如:

  • BIT[4] 代表数组中第1至第4个元素的和。
  • BIT[6] 代表数组中第5和第6个元素的和。

3. 基本操作的实现

Fenwick 树支持两种基本操作:

  1. 更新操作:将某个位置的元素增加一个值。
  2. 查询操作:求解前缀和,即从数组的起始位置到某个位置的区间和。
3.1 单点更新操作(Update)

更新操作的目标是将数组中的某个元素增加一个值,同时保持 Fenwick 树中相关的前缀和信息一致。

更新的具体过程是,从修改的那个元素开始,逐步将对应的树状数组中的父节点值更新。父节点的下标通过将当前下标的最低位为1的二进制位加到当前下标上来确定。

// 在 index 位置增加 delta 值
void update(int index, int delta, int[] BIT, int n) {while (index <= n) {BIT[index] += delta;index += index & -index;  // 移动到下一个需要更新的父节点}
}

update 操作中,index += index & -index 是通过获取下标 index 的最低有效位(Lowest Significant Bit, LSB)来确定下一个要更新的父节点的位置。

3.2 前缀和查询操作(Query)

查询操作的目标是求解从数组的起始位置到某个位置的区间和。Fenwick 树存储的是部分前缀和,因此可以通过逐步累加相关节点的值来计算结果。

// 查询从 1 到 index 的前缀和
int query(int index, int[] BIT) {int sum = 0;while (index > 0) {sum += BIT[index];index -= index & -index;  // 移动到下一个需要累加的父节点}return sum;
}

query 操作中,index -= index & -index 是通过获取下标 index 的最低有效位来确定下一个要查询的父节点。

4. Fenwick 树的实现

以下是一个 Fenwick 树的 Java 实现,包括对数组进行单点更新和前缀和查询的功能:

class FenwickTree {private int[] BIT;  // 树状数组private int n;      // 数组大小// 构造函数,初始化树状数组public FenwickTree(int size) {n = size;BIT = new int[n + 1];  // BIT[0] 不使用,因此数组长度为 n+1}// 单点更新操作:在 index 位置增加 deltapublic void update(int index, int delta) {while (index <= n) {BIT[index] += delta;index += index & -index;  // 移动到下一个需要更新的父节点}}// 查询操作:获取从 1 到 index 的前缀和public int query(int index) {int sum = 0;while (index > 0) {sum += BIT[index];index -= index & -index;  // 移动到下一个需要累加的父节点}return sum;}// 查询操作:获取区间 [l, r] 的和public int queryRange(int l, int r) {return query(r) - query(l - 1);}
}public class Main {public static void main(String[] args) {// 创建大小为10的树状数组FenwickTree fenwickTree = new FenwickTree(10);// 在位置3增加5fenwickTree.update(3, 5);// 查询前缀和(从位置1到5的和)System.out.println("前缀和1到5: " + fenwickTree.query(5)); // 输出: 5// 在位置6增加10fenwickTree.update(6, 10);// 查询区间和(从位置3到6的和)System.out.println("区间和3到6: " + fenwickTree.queryRange(3, 6)); // 输出: 15}
}

5. Fenwick 树的时间复杂度

  • 单点更新操作:每次更新需要沿着树向上更新父节点,更新的次数最多为树的高度,而树的高度是 O(log⁡n),因此更新的时间复杂度为 O(log n)
  • 前缀和查询操作:类似于更新操作,查询时沿着树向上累加相关节点的值,时间复杂度同样为 O(log n)

6. Fenwick 树与线段树的比较

  • 线段树Fenwick 树 都可以处理区间和查询以及单点更新问题,它们的时间复杂度都是 O(log⁡n)。
  • Fenwick 树实现简单,适用于单点更新和前缀和查询,但不支持灵活的区间更新(如区间加法),而线段树可以处理复杂的区间更新操作。
  • Fenwick 树的空间复杂度为 O(n),线段树的空间复杂度为 O(2n),因此 Fenwick 树在空间上具有一定的优势。

7. 应用场景

Fenwick 树的应用场景非常广泛,尤其适用于处理频繁的查询和更新操作。例如:

  1. 动态数组的区间和查询:Fenwick 树可以高效处理动态数组的前缀和问题,适用于需要频繁查询和修改的场景。
  2. 逆序对计算:在处理逆序对问题中,可以使用 Fenwick 树来快速统计数组中较小元素的个数,从而高效地解决问题。
  3. 二维 Fenwick 树:在一些高级应用场景中,Fenwick 树还可以扩展为二维,用于解决二维区域查询和更新问题。

8. 总结

Fenwick 树是一种高效解决前缀和问题的树状数组数据结构,适合处理动态更新和区间查询。它的核心思想是利用二进制性质进行分段存储,结合低效位来快速确定更新和查询的范围。与其他数据结构(如线段树)相比,Fenwick 树的实现更加简洁,适用于较为简单的区间查询和更新场景。


http://www.mrgr.cn/news/55109.html

相关文章:

  • 深度解析模型调优与正则化:L1、L2正则化及偏差-方差的权衡
  • 设计模式,面试级别的详解(持续更新中)
  • owasp top 10漏洞原理与防御技术(原理和对应防御技术)
  • 豆包大模型接口调用
  • wsl安装深度学习基础环境
  • 区块链技术原理
  • 在Smarty模板中如何用自定义函数
  • C#/.NET/.NET Core技术前沿周刊 | 第 10 期(2024年10.14-10.20)
  • JS数组去重
  • 【算法】小红的ABC
  • 关于region_to_label算子的想法
  • 【深度学习中的注意力机制2】11种主流注意力机制112个创新研究paper+代码——多头注意力机制(Multi-Head Attention, MHA)
  • AG32 MCU家族添加新成员
  • 汽车电子笔记之-014:一场FIFO的思考引发将汽车电子DTC相关 - 故障发生前后关键数据记录并回读的功能浅研发
  • edge浏览器:你的连接不是专用连接
  • Java获取指定目录下的文件名,并自定义排序
  • 关于鸿蒙学习之遇到的问题——ERROR: Invalid dependency entry
  • 神奇的数据结构 —— 跳表
  • 道路车辆功能安全 ISO 26262标准(6-1)—软件级产品开发
  • Java 异步编程——异步编排(CompletableFuture)
  • 三周精通FastAPI:4 使用请求从客户端(例如浏览器)向 API 发送数据
  • SCTF-2024-wp
  • LabVIEW换流变换器智能巡检系统
  • 流量分类实验
  • JAVA基础【第三篇】
  • JavaScript报错:Uncaught SyntaxError: Unexpected end of input(at test.html:1:16)