Fenwick tree Binary indexed tree | |
Type: | Binomial tree |
Invented By: | Boris Ryabko |
Invented Year: | 1989 |
A Fenwick tree or binary indexed tree (BIT) is a data structure that stores an array of values and can efficiently compute prefix sums of the values and update the values. It also supports an efficient rank-search operation for finding the longest prefix whose sum is no more than a specified value. Its primary use is operating on the cumulative distribution function of a statistical frequency table which is updated often.
This structure was proposed by Boris Ryabko in 1989[1] with a further modification published in 1992.[2] It has subsequently become known under the name Fenwick tree after Peter Fenwick, who described this structure in his 1994 article.[3]
A simple array of values is trivial (constant-time) to update but requires
O(n)
An array of prefix sums can return a prefix sum in constant time, and search for a prefix length in
O(logn)
O(n)
A Fenwick tree allows all three operations to be performed in
O(logn)
n+1
n
O(logn)
Given an array of values, it is sometimes desirable to calculate the running total of values up to each index according to some associative binary operation (addition on integers being by far the most common). Fenwick trees provide a method to query the running total at any index, or prefix sum, while allowing changes to the underlying value array and having all further queries reflect those changes.
Fenwick trees are particularly designed to implement the arithmetic coding algorithm, which maintains counts of each symbol produced and needs to convert those to the cumulative probability of a symbol less than a given symbol. Development of operations it supports were primarily motivated by use in that case.
A Fenwick tree is an implicit tree where nodes are consecutively numbered, and parent-child relationships are determined by arithmetic on the node indexes.
An important function in this index arithmetic is the least significant set bit, also called the find first set operation. This is the greatest power of two which divides an index
i
\operatorname{lsb}(i)=in\&-i
A[n]
n
A(i,j]=\{A[k]
j, | |
\} | |
k=i+1 |
i
j
F[n]
styleF[i]=\sumA(i-\operatorname{lsb}(i),i]
\operatorname{lsb}(i)
A[i]
A fictitious node 0 is used in some descriptions, but is never actually accessed and need not be explicitly stored.
\operatorname{lsb}(0)=infty,
F[0]
A(0,0]=\{\}
A "Fenwick tree" is actually three implicit trees over the same array: the interrogation tree used for translating indexes to prefix sums, the update tree used for updating elements, and the search tree for translating prefix sums to indexes (rank queries).[4] The first two are normally walked upwards, while the third is usually walked downwards.
The interrogation tree is defined so that the parent of node
i
i-\operatorname{lsb}(i)=in\&(i-1)
Each level
k
k
k=0
k=1
1=20,2=21,4=22,...
k=2
3=21+20,5=22+20,6=22+21,...
Node
i
log2(\operatorname{lsb}(i))
i+1,i+2,i+4,...,i+\operatorname{lsb}(i)/2
\operatorname{lsb}(i)
n
The below diagram shows the structure of a 16-node Fenwick tree's interrogation tree, including the root, so it corresponds to a 15-element array A:
To find the prefix sum
A[1]+ … +A[i]
i
A[i]+ … +A[j]
i-1
j
This can be optimized by stopping at their first common ancestor. An extreme example is asking for a single entry
A[j]
j
i=j-1
j-\operatorname{lsb}(j)
F[j]
i ≠ j-\operatorname{lsb}(j)
F[i]
i := i - lsb(i)
.The update tree is the mirror image of the interrogation tree. The parent of node
i
i+\operatorname{lsb}(i)=(in|(i-1))+1
This conceptual tree is infinite, but only the part with indexes up to
n
n
n
Here, a node's ancestors are all nodes whose range sums include its own. For example,
F[6]
A(4,6]
F[8]
A(0,8]
To modify one of the values
A[i]
F[i]
i
n
Unlike the other two trees, the search tree is a binary tree, arranged in an order Knuth calls a "sideways heap". Each node is assigned a height equal to the number of trailing zeros in the binary representation of its index, with the parent and children being the numerically closest index(es) of the adjacent height. Nodes with odd indexes (
\operatorname{lsb}(i)=1
i\pm\operatorname{lsb}(i)/2
i
(i-\operatorname{lsb}(i))n|(2 ⋅ \operatorname{lsb}(i))
For example, the children of 6 = 1102 are 5 = 1012 and 7 = 1112, and its parent is 4 = 1002.
Although this tree is potentially infinite, we may define its root to be the highest existing node, whose index is the greatest power of 2 less than or equal to
n
It is possible for a node to have a fictitious parent with an index greater than
n
The search tree may be considered a combination of the previous two trees. A node's left subtree contains all of its descendants in the update tree, while its right subtree contains all of its descendants in the interrogation tree. A node's parent in the search tree is either its interrogation or update parent (depending on whether the node is a right or left child, respectively), and the other type of parent may be found by multiple upward steps in the search tree.
However, upward traversals in the search tree are uncommon; its primary use is to perform rank queries: given a prefix sum, at what index does it appear? This is done by a downward traversal through the search tree. During the traversal, three variables are maintained: The current node's index, the rank being sought in the subtree rooted at the current node, and a "fallback index" to be returned if the rank sought is greater than can be found in the subtree.
Initially, the current node is the root, the rank sought is the original query, and the fallback index is a special "overflow" value indicating that the rank is not in the tree. (Depending on the application,
0
n+1
Each step, either the current node is a fictitious node (index greater than
n
F[i]
These three possibilities are then further divided based on whether the current node is a leaf or not:
A simple pseudocode implementation of the two main operations on a Fenwick tree—query and update—is as following:
function query(tree, index) is sum := 0 while index > 0 do sum += tree[index] index -= lsb(index) return sum function update(tree, index, value) is while index < size(tree) do tree[index] += value index += lsb(index)
The function
lsb(n)
n
n
lsb(20)=4
lsb(10bf{1}002)=1002=4
lsb(n) = n & (-n)
, assuming two's complement negation.[3] One naïve algorithm to construct a Fenwick tree consists of initializing the tree with null values and updating each index individually. This solution works in
O(nlog{n})
O(n)
function construct(values) is tree := values for index from 1 to size(tree) do parentIndex := index + lsb(index) if parentIndex ≤ size(tree) then tree[parentIndex] += tree[index] return tree