From 882ba119dcc55f02776a8948127bd5d66b7682ff Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 21 Jul 2023 12:16:15 -0600 Subject: [PATCH] [feat/docs]: improve Fenwick Tree algorithm (#2506) * [feat/docs]: improve Fenwick Tree algorithm * chore: apply suggestions from code review Co-authored-by: Taj --------- Co-authored-by: Taj Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com> --- range_queries/fenwick_tree.cpp | 131 +++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 39 deletions(-) diff --git a/range_queries/fenwick_tree.cpp b/range_queries/fenwick_tree.cpp index a2498dc6a..d1db65dc5 100644 --- a/range_queries/fenwick_tree.cpp +++ b/range_queries/fenwick_tree.cpp @@ -1,48 +1,78 @@ /** * @file - * @brief Fenwick tree + * @brief [Fenwick Tree](https://en.wikipedia.org/wiki/Fenwick_tree) algorithm + * implementation + * @details + * _From Wikipedia, the free encyclopedia._ * - * A Fenwick tree or binary indexed tree is a data structure - * that can efficiently update elements and calculate - * prefix sums in a table of numbers. + * A Fenwick tree or binary indexed tree (BIT) is a clever implementation of a + * datastructure called bionomal tree. It can update values and solve range + * queries with operations that is; commulative, associative and has an + * inverse for this type of element. It can also solve immutable range queries + * (min/max), when operations only are associative over this type of element. + * Some of these restrictions can be removed, by storing redunant information; + * like in max/min range queries. + * + * @author [Mateusz Grzegorzek](https://github.com/mateusz-grzegorzek) + * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include + +#include /// for assert +#include /// for IO operations +#include /// for std::vector /** - * n --> No. of elements present in input array. - * bit[0..n] --> Array that represents Binary Indexed Tree. + * @namespace + * @brief Range Queries */ -class FenwickTree { - int n; - std::vector bit; +namespace range_queries { +/** + * @brief The class that initializes the Fenwick Tree. + */ +class fenwick_tree { + size_t n = 0; ///< No. of elements present in input array + std::vector bit{}; ///< Array that represents Binary Indexed Tree. - /** Returns the highest power of two which is not more than x */ - inline int offset(int x) { return (x & (-x)); } - - public: - /** Constructor - * \param[in] arr --> Input array for which prefix sum is evaluated. + /** + * @brief Returns the highest power of two which is not more than `x`. + * @param x Index of element in original array. + * @return Offset of index. */ - explicit FenwickTree(const std::vector& arr) { - n = arr.size(); + inline int offset(int x) { return (x & (-x)); } + public: + /** + * @brief Class Constructor + * @tparam T the type of the array + * @param[in] arr Input array for which prefix sum is evaluated. + * @return void + */ + template + explicit fenwick_tree(const std::vector& arr) : n(arr.size()) { bit.assign(n + 1, 0); for (int i = 0; i < n; ++i) { update(i, arr[i]); } } - /** Constructor - * \param[in] x --> Size of array that represents Binary Indexed Tree. + /** + * @brief Class Constructor + * @tparam T the type of the variable + * @param[in] x Size of array that represents Binary Indexed Tree. + * @return void */ - explicit FenwickTree(int x) { - n = x; - bit.assign(n + 1, 0); - } + template + explicit fenwick_tree(T x) : n(x) { bit.assign(n + 1, 0); } - /** Add val at id */ - void update(int id, int val) { + /** + * @brief Updates the value of an element in original array and + * accordingly updates the values in BIT array. + * @tparam T the type of the variables + * @param id Index of element in original array. + * @param val Value with which element's value is updated. + * @return void + */ + template + void update(T id, T val) { id++; while (id <= n) { bit[id] += val; @@ -50,10 +80,16 @@ class FenwickTree { } } - /** Get prefix sum upto id */ - int sum(int id) { + /** + * @brief Returns the sum of elements in range from 0 to ID. + * @tparam T the type of the variables + * @param id Index in original array up to which sum is evaluated. + * @return Sum of elements in range from 0 to id. + */ + template + int sum(T id) { id++; - int res = 0; + T res = 0; while (id > 0) { res += bit[id]; id -= offset(id); @@ -61,22 +97,39 @@ class FenwickTree { return res; } - /** Returns the prefix sum in range from l to r */ + /** + * @brief Returns the prefix sum in range from L to R. + * @param l Left index of range. + * @param r Right index of range. + * @return Sum of elements in range from L to R. + */ int sum_range(int l, int r) { return sum(r) - sum(l - 1); } }; +} // namespace range_queries -/** Main function */ -int main() { - int n = 5; +/** + * @brief Self-test implementations + * @returns void + */ +static void tests() { std::vector arr = {1, 2, 3, 4, 5}; - FenwickTree fenwick_tree(arr); + range_queries::fenwick_tree fenwick_tree(arr); assert(fenwick_tree.sum_range(0, 0) == 1); assert(fenwick_tree.sum_range(0, 1) == 3); assert(fenwick_tree.sum_range(0, 2) == 6); + assert(fenwick_tree.sum_range(0, 3) == 10); + assert(fenwick_tree.sum_range(0, 4) == 15); + fenwick_tree.update(0, 6); - assert(fenwick_tree.sum_range(0, 0) == 6); - assert(fenwick_tree.sum_range(0, 1) == 8); - assert(fenwick_tree.sum_range(0, 2) == 11); + std::cout << "All tests have successfully passed!\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + tests(); // run self-test implementations return 0; }