树状数组或二元索引树(英语:Binary Indexed Tree),又以其发明者命名为Fenwick树,最早由Peter M. Fenwick于1994年以A New Data Structure for Cumulative Frequency Tables为题发表在SOFTWARE PRACTICE AND EXPERIENCE。其初衷是解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和, 区间和。它可以以在O(log n)的时间得到任意前缀和,并同时支持在O(log n)时间内支持动态单点值的修改。空间复杂度O(n)。
package IndexTree
import (
"math/rand"
"testing"
"time"
)
/*
和堆很像,最终压缩到数组内
1
/ \
2 3
/ \ / \
4 5 6 7
[1,2,3,4,5,6,7]
HEAP
parent: k
left_child: 2k + 1
right_child: 2k + 2
BINARY_INDEXED_TREE
no 1bit 0
/ / | \
/ / | \
one 1bits 1 2 4 8
/ / \ / \ \
two 1bits 3 5 6 9 10 12
/ | / \
three 1bits 7 11 13 14
第0层 没有 1 bit位
第1层 有一个 1 bit位
第2层 有两个 1 bit位
第3层 有三个 1 bit位
...
第64层 有六十四个 1 bit位
parent to child
parent 0000 (0)
/ / \ \
children 0001(1) 0010(2) 0100(3) 1000(4)
从父节点找孩子:拥有父亲节点的二进制1比特个数加1个的所有数字
child to parent
0000(0)
/
0100(4)
/ \
0101(5) 0110(6)
/
0111(7)
从孩子节点找父节点: 孩子节点二进制去掉右侧的1比特的数字
[ 1 7 3 0 5 8 3 2 6 2 1 1 4 5 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 8 11 29
[1,1] [1,2] [1,4] [1,8]
3 5 13 6 8 10
[3,3] [5,5] [5,6] [9,9] [9,10] [9,12]
3 1 4 9
[7,7] [11,11] [13,13][13,14]
[ 1 8 3 11 5 13 3 29 6 8 1 10 4 9 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
引入前缀和,每层都有一个新的和
[ 1 7 3 0 5 8 3 2 6 2 1 1 4 5 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 8 11 29 <------------------------
[1,1] [1,2] [1,4] [1,8] |
3 5 13 6 8 10 <---
[3,3] [5,5] [5,6] [9,9] [9,10] [9,12] |
3 1 4 9
[7,7] [11,11] [13,13][13,14]
SUM(13) = RANGE(1,8) + RANGE(9,12) + RANGE(13,13)
13: 拆分成 2进制的形式 13 = 8 + 4 + 1 即: 1101
*/
type IndexTree struct { // 下标从1开始!
tree []int
N int
}
func NewIndexTree(size int) *IndexTree {
return &IndexTree{
tree: make([]int, size+1), // 0位置弃而不用
N: size,
}
}
// 1 ~ index 累加和是多少 log(N)
func (it *IndexTree) sum(index int) int {
res := 0
for ; index > 0; index -= index & (-index) {
res += it.tree[index]
}
return res
}
// index & -index : 提取出index最右侧的1出来
// index : 0011001000
// index & -index : 0000001000
// log(N)
func (it *IndexTree) add(index, d int) {
for ; index <= it.N; index += index & (-index) {
it.tree[index] += d
}
}
type right struct {
nums []int
n int
}
func NewRight(size int) *right {
return &right{
nums: make([]int, size+1),
n: size,
}
}
func (r *right) sum(index int) int {
res := 0
for i := 1; i <= index; i++ {
res += r.nums[i]
}
return res
}
func (r *right) add(index, d int) {
r.nums[index] += d
}
func TestIndexTree(t *testing.T) {
N := 100
V := 100
testTimes := 2000000
tree := NewIndexTree(N)
test := NewRight(N)
t.Log("开始测试")
rand.Seed(time.Now().UnixNano())
for i := 0; i < testTimes; i++ {
index := rand.Int()%N + 1
if rand.Float64() <= 0.5 {
n := rand.Int() % V
tree.add(index, n)
test.add(index, n)
} else {
if tree.sum(index) != test.sum(index) {
t.Log(tree.sum(index), test.sum(index))
t.Log(tree)
t.Log(test)
panic("不相等")
}
}
}
t.Log("测试完成")
}
维基百科
https://zh.wikipedia.org/wiki/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84