Welcome to WENBIN's cnblogs.|

cnblogs_wb

园龄:2年6个月粉丝:0关注:0

数据结构 - 树状数组 Binary Indexed Tree

在算法竞赛和实际应用中,处理动态数据时经常遇到以下问题:

  • 区间求和:快速求解某个区间的元素总和;
  • 单点更新:快速更新某个元素的值,同时保证区间查询结果的正确性。

如果使用简单的数组实现,区间查询的复杂度为 O(n),单点更新的复杂度为 O(1)。而如果选用前缀和数组,查询变成了 O(1),但更新需要 O(n)。如何同时兼顾高效的查询与更新呢?树状数组,也成为二叉索引树(Binary Indexed Tree)提供了优雅的解决方案,其查询与更新的时间复杂度均为 O(logn)。本文将深入讲解树状数组的原理、实现与应用。

1. 什么是树状数组

树状数组的核心是通过数组下标的二进制特性,将数据划分为不同的区间。每个数组元素存储一个子区间的累加值,利用这些部分和快速计算前缀和或更新元素。其特性如下:

  • 树状数组的本质是一棵隐式的二叉索引树,存储在一个一维数组中;
  • 下标 i 的元素存储的是区间 [i2r+1,i] 的和,其中 ri 的二进制表示中最低位 1 的位置。例如:
    • i=4(二进制为 100),维护区间 [1,4]
    • i=6(二进制为 110),维护区间 [5,6]

2. 树状数组的基本操作

2.1 单点更新

更新某个下标元素值时,需要修改受影响的所有区间值。更新规则是:

ii+lowbit(i)

其中,lowbit(i) 表示 i 的二进制中最低位 1 所代表的值,可以通过位运算求得:

lowbit(i)=i&(i)

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

void update(int index, int delta) {
    while (index <= tree.size()) {
        tree[index] += delta;
        idx += lowbit(index);
    }
}

2.2 前缀和查询

查询数组前 i 个元素的前缀和时,只需累加相关区间的值即可。查询规则为:

iilowbit(i)

int query(int index) {
    int sum = 0;
    while (index > 0) {
        sum += tree[index];
        index -= lowbit(index);
    }
    return sum;
}

如果需要查询的是区间 [l,r] 内元素的和,那么可以转化为对区间 [1,r] 和区间 [1,l1] 前缀和的查询再做差分。

3. 树状数组的复杂度分析

  • 时间复杂度:修改和查询操作的时间复杂度都是 O(logn)
  • 空间复杂度:O(n)

4. 树状数组的模板

class BinaryIndexedTree {
public:
    BinaryIndexedTree(int n) {
        tree.resize(n + 1, 0);
    }

    void update(int index, int delta) {
        while (index < tree.size()) {
            tree[index] += delta;
            index += lowbit(index);
        }
    }

    int query(int index) {
        int sum = 0;
        while (index > 0) {
            sum += tree[index];
            index -= lowbit(index);
        }
        return sum;
    }

    int rangeQuery(int left, int right) {
        return query(right) - query(left - 1);
    }

private:
    std::vector<int> tree;
    
    int lowbit(int x) {
        return x & (-x);
    }
};

5. 实例

307. 区域和检索 - 数组可修改 - 力扣(LeetCode)

308. 二维区域和检索 - 矩阵可修改 - 力扣(LeetCode)

本文作者:cnblogs_wb

本文链接:https://www.cnblogs.com/wenbinteng/p/18734101

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   cnblogs_wb  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示