Skip to content

Commit 17405a0

Browse files
manncodesgithub-actionsPanquesito7ayaankhan98
authored
feat: add spare table data structure (TheAlgorithms#1502)
* feat: add spare table data structure Added implementation of sparse table for a 'duplicate invariant function'. Implementation of min(a1,a2...,aN) being the duplicate invariant function is done. * fixed: clang-tidy warnings * minor change: remove bits/stdc++ header * added header comments * updating DIRECTORY.md * fixed to clang-format * fixed header postion suggested change Co-authored-by: David Leal <halfpacho@gmail.com> * fixed author name suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * fixed test() info to Doxygen standards. suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * changed comment suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * minor changes in file info suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * minor changes in file info suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * minor changes in file info suggested changes Co-authored-by: David Leal <halfpacho@gmail.com> * changes in variable and struct descriptions * Update data_structures/sparse_table.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update data_structures/sparse_table.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update data_structures/sparse_table.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * changed int data type for non-negative numbers * changing datatypes of certain variables * Update data_structures/sparse_table.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update data_structures/sparse_table.cpp Co-authored-by: Ayaan Khan <ayaankhan98@gmail.com> * clang-format and clang-tidy fixes for ddf777f * minor changes * fixed comparison of integer of diff signedness * Update data_structures/sparse_table.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * added description as @Panquesito7 suggested * minor grammar checks * minor documentation fixes Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: Ayaan Khan <ayaankhan98@gmail.com>
1 parent 5ba8bc2 commit 17405a0

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
* [Queue Using Two Stacks](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/queue_using_two_stacks.cpp)
4848
* [Rb Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/rb_tree.cpp)
4949
* [Skip List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/skip_list.cpp)
50+
* [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/sparse_table.cpp)
5051
* [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack.h)
5152
* [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_array.cpp)
5253
* [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_linked_list.cpp)

data_structures/sparse_table.cpp

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/**
2+
* @file
3+
* @brief Implementation of [Sparse
4+
* Table](https://brilliant.org/wiki/sparse-table/) for `min()` function.
5+
* @author [Mann Patel](https://github.com/manncodes)
6+
* @details
7+
* Sparse Table is a data structure, that allows answering range queries.
8+
* It can answer most range queries in O(logn), but its true power is answering
9+
* range minimum queries (or equivalent range maximum queries). For those
10+
* queries it can compute the answer in O(1) time. The only drawback of this
11+
* data structure is, that it can only be used on immutable arrays. This means,
12+
* that the array cannot be changed between two queries.
13+
*
14+
* If any element in the array changes, the complete data structure has to be
15+
* recomputed.
16+
*
17+
* @todo make stress tests.
18+
*
19+
* @warning
20+
* This sparse table is made for `min(a1,a2,...an)` duplicate invariant
21+
* function. This implementation can be changed to other functions like
22+
* `gcd()`, `lcm()`, and `max()` by changing a few lines of code.
23+
*/
24+
25+
#include <array> /// for std::array
26+
#include <cassert> /// for assert
27+
#include <iostream> /// for IO operations
28+
29+
/**
30+
* @namespace data_structures
31+
* @brief Data Structures algorithms
32+
*/
33+
namespace data_structures {
34+
35+
/**
36+
* @namespace sparse_table
37+
* @brief Functions for Implementation of [Sparse
38+
* Table](https://brilliant.org/wiki/sparse-table/)
39+
*/
40+
namespace sparse_table {
41+
42+
/**
43+
* @brief A struct to represent sparse table for `min()` as their invariant
44+
* function, for the given array `A`. The answer to queries are stored in the
45+
* array ST.
46+
*/
47+
constexpr uint32_t N = 12345; ///< the maximum size of the array.
48+
constexpr uint8_t M = 14; ///< ceil(log2(N)).
49+
50+
struct Sparse_table {
51+
size_t n = 0; ///< size of input array.
52+
53+
/** @warning check if `N` is not less than `n`. if so, manually increase the
54+
* value of N */
55+
56+
std::array<int64_t, N> A = {}; ///< input array to perform RMQ.
57+
std::array<std::array<int64_t, N>, M>
58+
ST{}; ///< the sparse table storing `min()` values for given interval.
59+
std::array<int64_t, N> LOG = {}; ///< where floor(log2(i)) are precomputed.
60+
61+
/**
62+
* @brief Builds the sparse table for computing min/max/gcd/lcm/...etc
63+
* for any contiguous sub-segment of the array.This is an example of
64+
* computing the index of the minimum value.
65+
* @return void
66+
* @complexity: O(n.log(n))
67+
*/
68+
void buildST() {
69+
LOG[0] = -1;
70+
71+
for (size_t i = 0; i < n; ++i) {
72+
ST[0][i] = static_cast<int64_t>(i);
73+
LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)`
74+
}
75+
76+
for (size_t j = 1; static_cast<size_t>(1 << j) <= n; ++j) {
77+
for (size_t i = 0; static_cast<size_t>(i + (1 << j)) <= n; ++i) {
78+
/**
79+
* @note notice how we deal with the range of length `pow(2,i)`,
80+
* and we can reuse the computation that we did for the range of
81+
* length `pow(2,i-1)`.
82+
*
83+
* So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]).
84+
* @example ST[2][3] = min(ST[1][3], ST[1][5])
85+
*/
86+
87+
int64_t x = ST[j - 1][i]; ///< represents minimum value over
88+
///< the range [j,i]
89+
int64_t y =
90+
ST[j - 1]
91+
[i + (1 << (j - 1))]; ///< represents minimum value over
92+
///< the range [j,i + pow(2,j-1)]
93+
94+
ST[j][i] =
95+
(A[x] <= A[y] ? x : y); ///< represents minimum value over
96+
///< the range [j,i]
97+
}
98+
}
99+
}
100+
101+
/**
102+
* @brief Queries the sparse table for the value of the interval [l, r]
103+
* (i.e. from l to r inclusive).
104+
* @param l the left index of the range (inclusive).
105+
* @param r the right index of the range (inclusive).
106+
* @return the computed value of the given interval.
107+
* @complexity: O(1)
108+
*/
109+
int64_t query(int64_t l, int64_t r) {
110+
int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r]
111+
int64_t x = ST[g][l]; ///< represents minimum value over the range
112+
///< [g,l]
113+
int64_t y =
114+
ST[g][r - (1 << g) + 1]; ///< represents minimum value over the
115+
///< range [g, r - pow(2,g) + 1]
116+
117+
return (A[x] <= A[y] ? x : y); ///< represents minimum value over
118+
///< the whole range [l,r]
119+
}
120+
};
121+
} // namespace sparse_table
122+
} // namespace data_structures
123+
124+
/**
125+
* @brief Self-test implementations
126+
* @returns void
127+
*/
128+
static void test() {
129+
/* We take an array as an input on which we need to perform the ranged
130+
* minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query).
131+
*/
132+
std::array<int64_t, 10> testcase = {
133+
1, 2, 3, 4, 5,
134+
6, 7, 8, 9, 10}; ///< array on which RMQ will be performed.
135+
size_t testcase_size =
136+
sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array
137+
138+
data_structures::sparse_table::Sparse_table
139+
st{}; ///< declaring sparse tree
140+
141+
std::copy(std::begin(testcase), std::end(testcase),
142+
std::begin(st.A)); ///< copying array to the struct
143+
st.n = testcase_size; ///< passing the array's size to the struct
144+
145+
st.buildST(); ///< precomputing sparse tree
146+
147+
// pass queries of the form: [l,r]
148+
assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9
149+
assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6
150+
assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8
151+
152+
std::cout << "Self-test implementations passed!" << std::endl;
153+
}
154+
155+
/**
156+
* @brief Main function
157+
* @param argc commandline argument count (ignored)
158+
* @param argv commandline array of arguments (ignored)
159+
* @returns 0 on exit
160+
*/
161+
int main(int argc, char *argv[]) {
162+
test(); // run self-test implementations
163+
return 0;
164+
}

0 commit comments

Comments
 (0)