吃透 Binary Indexed Trees (树状数组)

简介

Binary Indexed Trees(中文名为树状数组,下文简称为BIT)是一种特殊的数据结构,适用于高效计算数列的前缀和区间和

时间复杂度:

  1. 任意前缀和、区间和:O(logn)
  2. 单点值修改:O(logn)

空间复杂度: O(n)

虽然 BIT 名称中带有 tree 这个词,但是实际存储时是利用数组进行存储,记nums为原始数组和 BIT为 BIT 数组,我们观察的是nums,但实际操作的是BIT
下图就是初始化后的BIT情况,横轴为数组的下标i,纵轴为下标数值对应的lowestbit,长方形表示BIT[i]涵盖的元素的范围。

image

可以看到每个数组下标的lowestbit(也就是图中描黑的部分)在形态上构成了一棵树的形状,这也是名称中 tree 的来源。并且对于每个下标表示成的tree node有以下特性。

(1)假如i是左子节点,那么其父节点下标为i + lowestbit(i),节点 4 为左子节点,父节点为节点 8( 4 + lowestbit(4) = 4 + (100) = 4 + 4 = 8
(2)假如i是右子节点,那么其父节点下标为i - lowestbit(i),节点 12 为左子节点,父节点为节点 8 ( 12 - lowestbit(12) = 12 - (100) =12 - 4 = 8

上面这两个特性非常重要,也是我们进行后文分析的重要基础。

更新数值

由图可知,BIT 中某些节点是包含其他节点的值得,所以在更新节点时,要同时更新这些包含节点的节点,例如更新节点 6 时,由于节点 8 和节点 16 包含节点 6 的值,所以也需要更新,那么如何判断更新节点 6 时,需要同时更新的节点是 8 和 16 呢?
若是按照树结构来找:

  1. 先找节点 6 的父节点 6 - lowestbit(6) = 4
  2. 找节点 4 的父节点 4 + lowestbit(4) = 8
  3. 找节点 8 的父节点 8 + lowestbit(8) = 16
  4. 共找到节点 4 8 16 三个节点
  5. 其中节点 6 在节点 4 的右子树中,所以节点 4 是不包含节点 6 的
  6. 节点 6 在节点 8 16 的左子树中,包含节点 6
  7. 所以更新节点 8 16

这是顺序逻辑,那有没有办法直接越过节点 4 ,而去寻找节点 8 16 呢?

观察图就可以发现,对于节点 6 而言,它与父节点 4 的距离,跟与祖节点 8 的距离是一样的,都是lowestbit(6) = 2
那么我们就可以用6 + lowestbit(6) = 8的方式来越过节点 4 直接寻找到节点 8。
6 + lowestbit(6)与左子节点寻找父节点公式i + lowestbit(i)相同,所以寻找含有节点 6 的节点 8 16,我们可以只用i + lowestbit(i)来完成:

while(i < BIT.length)
{
    BIT[i] += offset
    i = i + lowestbit(i)
}

区间求和

如若求 nums 前 n 个元素的和,观察图可知,将此节点以及不断获取其作为右节点时的父节点,然后加和就可以了。

var sum = 0
while(i > 0)
{
    sum += BIT[i]
    i = i - lowestbit(i)
}

例如求 nums[0, 7] 的和,则通过上述代码和分别获得 BIT[7]、 BIT[6]、 BIT[4],sum = BIT[7] + BIT[6] + BIT[4],即为结果。
若是求区间和的话,例如 nums[5, 10],则是 nums[0, 10] - nums[0, 5] 即可。

参考:Binary Indexed Trees 简介(重点帮助我理解了树状数组的结构,以及 i - lowestbit(i)、i + lowestbit(i) 与节点的关系,里面的BIT[i]公式感觉并不正确)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,815评论 0 5
  • 排序算法几种分类方式: 1,稳定排序和不稳定排序 如果a==b, 当排序之前a在b的前面,排序后,a仍然在b...
    fly_ever阅读 404评论 0 0
  • 堆是一棵满足一定性质的二叉树,具体的讲堆具有如下性质:父节点的键值总是不大于它的孩子节点的键值(小顶堆), 堆可以...
    9527Roy阅读 611评论 0 0
  • 基本数据结构中,数组是很重要的,这篇小猿圈加加对数组详解一席,具体使用,在学习过程中有困惑的朋友,可以看一下加加的...
    小猿圈加加阅读 473评论 0 0
  • 树状数组能解决的问题 树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick ...
    李威威阅读 1,252评论 0 3