树状数组
今天把树状数组详细看来一下。主要浏览的有:
http://zh.wikipedia.org/wiki/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84
http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html
树状数组(Binary Indexed Trees,二分索引树),最早由Peter M. Fenwick于1994年以A New Data Structure for Cumulative Frequency Tables为题发表在SOFTWARE PRACTICE AND EXPERIENCE。其初衷是解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和(\sum_{i=1}^N a[i])。它可以以O(log n)的时间得到\sum_{i=1}^N a[i],并同样以O(log n)对某项加一个常数。
=这是一个很好的建模思想,如何把O(n)的线性问题,通过建模,改变结构,优化成O(log)的思想。
=除了上文链接中的定义和代码,额外记录一下感悟,重要从这个方案的产生角度来思考。
Fenvick当时手头上的任务估计是:一个大的数据库,数据会时常更新,而Fenvick在每次更新的时候,要做一次求和。针对于以亿记的超大量数据,每次求和都完整的重新计算一遍,对于只有一两个数据变化的情况,如此重复的计算显然是Fenvick无法接受的,也是笃定地认为可以优化的。已经是O(n),就要考虑O(logn)了,在设计的时候充分利用只有一两个数据发生改变的条件,进行建模。经过一系列复杂的过程,balabala,就出现上面那张图了。
其实也可以是完完全全的完全二叉树或三叉树,每次有数据发生变化同样可以在Log2(n),Log3(n)之内,重新调整那些变化节点,即树的高度,那些‘小和节点‘。而上图的设计好处是:使用的偏树的设计,使得新增的数组节点对树状数组节点值的影响最小,同时新增数组节点对树状数组的结构变化很小,而且虽说是树,但只是tree-like,通过其设计的结构,完完全全可以把树的维护抛到九霄云外,常数时间内,可以直接定位任何树节点。所以学习之后,非常感慨Fenvick的设计。