Skip to content

Commit 76d17db

Browse files
feat(docs): document Fenwick tree (#92)
1 parent 189813b commit 76d17db

File tree

1 file changed

+101
-35
lines changed

1 file changed

+101
-35
lines changed

src/data_structures/fenwick_tree.rs

Lines changed: 101 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,135 @@
11
use std::ops::{Add, AddAssign};
22

3-
/// Fenwick Tree / Binary Indexed Tree
4-
/// Consider we have an array arr[0 . . . n-1]. We would like to
3+
/// A Fenwick Tree (also known as a Binary Indexed Tree) is a data structure
4+
/// that can efficiently update elements and calculate prefix sums in a table of numbers.
5+
///
6+
/// If we have an array arr[0 . . . n-1]. We would like to:
57
/// 1. Compute the sum of the first i elements.
6-
/// 2. Modify the value of a specified element of the array arr[i] = x where 0 <= i <= n-1.Fenwick tree
8+
/// 2. Modify the value of a specified element of the array arr[i] = x
9+
/// where 0 <= i <= n-1.
10+
///
11+
/// A simple solution is to run a loop from 0 to i-1 and calculate the sum of the elements.
12+
/// To update a value, simply do arr[i] = x. The first operation takes O(n) time and the
13+
/// second operation takes O(1) time. Another simple solution is to create an extra array and
14+
/// store the sum of the first i elements at the i-th index in this new array. The sum of a given
15+
/// range can be calculated in O(1) time, but the update operation takes O(n) time now. This works
16+
/// well if the number of query operations is large and the number of update operations is small.
17+
///
18+
/// The Fenwick tree provides a way to represent an array of numbers and perform two operations
19+
/// in O(log n) time.
20+
///
21+
/// The two operations are:
22+
/// 1. Update: Given a number x and an index i, we need to add x to the i-th element.
23+
/// 2. Query: Given an index i, we need to calculate the prefix sum of the first i elements.
24+
///
25+
/// The Fenwick tree is represented as an array of n elements. The tree structure allows us to
26+
/// perform efficient queries and updates. The tree is constructed in such a way that the value
27+
/// of each node is the sum of the values of the nodes in its subtree.
28+
///
729
pub struct FenwickTree<T: Add + AddAssign + Copy + Default> {
830
data: Vec<T>,
931
}
1032

1133
impl<T: Add<Output = T> + AddAssign + Copy + Default> FenwickTree<T> {
12-
/// construct a new FenwickTree with given length
34+
/// Create a new FenwickTree with length `len`
35+
///
36+
/// # Arguments
37+
///
38+
/// * `len` - The length of the FenwickTree
39+
///
40+
/// # Example
41+
///
42+
/// ```rust
43+
/// use rust_algorithms::data_structures::FenwickTree;
44+
///
45+
/// let mut ft = FenwickTree::with_len(10);
46+
/// ft.add(0, 1);
47+
/// ft.add(1, 2);
48+
///
49+
/// assert_eq!(ft.prefix_sum(0), 1);
50+
/// assert_eq!(ft.prefix_sum(1), 3);
51+
/// ```
1352
pub fn with_len(len: usize) -> Self {
1453
FenwickTree {
1554
data: vec![T::default(); len + 1],
1655
}
1756
}
1857

19-
/// add `val` to `idx`
58+
/// Add `val` to the `i`-th element
59+
///
60+
/// # Arguments
61+
///
62+
/// * `i` - The index of the element to add `val` to
63+
/// * `val` - The value to add to the `i`-th element
64+
///
65+
/// # Example
66+
///
67+
/// ```rust
68+
/// use rust_algorithms::data_structures::FenwickTree;
69+
///
70+
/// let mut ft = FenwickTree::with_len(10);
71+
/// ft.add(0, 3);
72+
/// ft.add(1, 2);
73+
///
74+
/// assert_eq!(ft.prefix_sum(0), 3);
75+
/// assert_eq!(ft.prefix_sum(1), 5);
76+
/// ```
2077
pub fn add(&mut self, i: usize, val: T) {
2178
assert!(i < self.data.len());
79+
2280
let mut i = i + 1;
81+
2382
while i < self.data.len() {
2483
self.data[i] += val;
2584
i += lowbit(i);
2685
}
2786
}
2887

29-
/// get the sum of [0, i]
88+
/// Get the prefix sum of the first `i` elements
89+
///
90+
/// # Arguments
91+
///
92+
/// * `i` - The index of the last element to calculate the prefix sum of
93+
///
94+
/// # Example
95+
///
96+
/// ```rust
97+
/// use rust_algorithms::data_structures::FenwickTree;
98+
///
99+
/// let mut ft = FenwickTree::with_len(10);
100+
/// ft.add(0, 1);
101+
/// ft.add(1, 2);
102+
/// ft.add(2, 3);
103+
/// ft.add(3, 4);
104+
/// ft.add(4, 5);
105+
/// ft.add(5, 6);
106+
/// ft.add(6, 7);
107+
/// ft.add(7, 8);
108+
/// ft.add(8, 9);
109+
/// ft.add(9, 10);
110+
///
111+
/// assert_eq!(ft.prefix_sum(0), 1);
112+
/// assert_eq!(ft.prefix_sum(1), 3);
113+
/// assert_eq!(ft.prefix_sum(2), 6);
114+
/// assert_eq!(ft.prefix_sum(3), 10);
115+
/// assert_eq!(ft.prefix_sum(4), 15);
116+
/// assert_eq!(ft.prefix_sum(5), 21);
117+
/// assert_eq!(ft.prefix_sum(6), 28);
118+
/// assert_eq!(ft.prefix_sum(7), 36);
119+
/// assert_eq!(ft.prefix_sum(8), 45);
120+
/// assert_eq!(ft.prefix_sum(9), 55);
121+
/// ```
30122
pub fn prefix_sum(&self, i: usize) -> T {
31123
assert!(i < self.data.len());
124+
32125
let mut i = i + 1;
33126
let mut res = T::default();
127+
34128
while i > 0 {
35129
res += self.data[i];
36130
i -= lowbit(i);
37131
}
132+
38133
res
39134
}
40135
}
@@ -44,32 +139,3 @@ const fn lowbit(x: usize) -> usize {
44139
let x = x as isize;
45140
(x & (-x)) as usize
46141
}
47-
48-
#[cfg(test)]
49-
mod tests {
50-
use super::*;
51-
#[test]
52-
fn it_works() {
53-
let mut ft = FenwickTree::with_len(10);
54-
ft.add(0, 1);
55-
ft.add(1, 2);
56-
ft.add(2, 3);
57-
ft.add(3, 4);
58-
ft.add(4, 5);
59-
ft.add(5, 6);
60-
ft.add(6, 7);
61-
ft.add(7, 8);
62-
ft.add(8, 9);
63-
ft.add(9, 10);
64-
assert_eq!(ft.prefix_sum(0), 1);
65-
assert_eq!(ft.prefix_sum(1), 3);
66-
assert_eq!(ft.prefix_sum(2), 6);
67-
assert_eq!(ft.prefix_sum(3), 10);
68-
assert_eq!(ft.prefix_sum(4), 15);
69-
assert_eq!(ft.prefix_sum(5), 21);
70-
assert_eq!(ft.prefix_sum(6), 28);
71-
assert_eq!(ft.prefix_sum(7), 36);
72-
assert_eq!(ft.prefix_sum(8), 45);
73-
assert_eq!(ft.prefix_sum(9), 55);
74-
}
75-
}

0 commit comments

Comments
 (0)