diff --git a/DIRECTORY.md b/DIRECTORY.md index 7f3e1817d..6b744c8c8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -61,6 +61,7 @@ * [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack.h) * [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_array.cpp) * [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_linked_list.cpp) + * [Stack Using Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_queue.cpp) * [Test Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_queue.cpp) * [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack.cpp) * [Test Stack Students](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack_students.cpp) diff --git a/data_structures/stack_using_queue.cpp b/data_structures/stack_using_queue.cpp new file mode 100644 index 000000000..54a81a135 --- /dev/null +++ b/data_structures/stack_using_queue.cpp @@ -0,0 +1,126 @@ +/** + * @brief Stack Data Structure Using the Queue Data Structure + * @details + * Using 2 Queues inside the Stack class, we can easily implement Stack + * data structure with heavy computation in push function. + * + * References used: [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) + * @author [tushar2407](https://github.com/tushar2407) + */ +#include /// for IO operations +#include /// for queue data structure +#include /// for assert + +/** + * @namespace data_strcutres + * @brief Data structures algorithms + */ +namespace data_structures { +/** + * @namespace stack_using_queue + * @brief Functions for the [Stack Using Queue](https://www.studytonight.com/data-structures/stack-using-queue) implementation + */ +namespace stack_using_queue { + /** + * @brief Stack Class implementation for basic methods of Stack Data Structure. + */ + struct Stack + { + std::queue main_q; ///< stores the current state of the stack + std::queue auxiliary_q; ///< used to carry out intermediate operations to implement stack + uint32_t current_size = 0; ///< stores the current size of the stack + + /** + * Returns the top most element of the stack + * @returns top element of the queue + */ + int top() + { + return main_q.front(); + } + + /** + * @brief Inserts an element to the top of the stack. + * @param val the element that will be inserted into the stack + * @returns void + */ + void push(int val) + { + auxiliary_q.push(val); + while(!main_q.empty()) + { + auxiliary_q.push(main_q.front()); + main_q.pop(); + } + swap(main_q, auxiliary_q); + current_size++; + } + + /** + * @brief Removes the topmost element from the stack + * @returns void + */ + void pop() + { + if(main_q.empty()) { + return; + } + main_q.pop(); + current_size--; + } + + /** + * @brief Utility function to return the current size of the stack + * @returns current size of stack + */ + int size() + { + return current_size; + } + }; +} // namespace stack_using_queue +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + data_structures::stack_using_queue::Stack s; + s.push(1); /// insert an element into the stack + s.push(2); /// insert an element into the stack + s.push(3); /// insert an element into the stack + + assert(s.size()==3); /// size should be 3 + + assert(s.top()==3); /// topmost element in the stack should be 3 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==2); /// topmost element in the stack should now be 2 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==1); + + s.push(5); /// insert an element into the stack + assert(s.top()==5); /// topmost element in the stack should now be 5 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==1); /// topmost element in the stack should now be 1 + + assert(s.size()==1); /// size should be 1 +} + +/** + * @brief Main function + * Creates a stack and pushed some value into it. + * Through a series of push and pop functions on stack, + * it demostrates the functionality of the custom stack + * declared above. + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/range_queries/segtree.cpp b/range_queries/segtree.cpp index 602b3fd95..bc03b5428 100644 --- a/range_queries/segtree.cpp +++ b/range_queries/segtree.cpp @@ -1,79 +1,218 @@ -//#include -#incldue < iostream > -#define MAX 4000000 -using namespace std; -typedef long long ll; -void ConsTree(ll arr[], ll segtree[], ll low, ll high, ll pos) { +/** + * @file + * @brief Implementation of [Segment Tree] + * (https://en.wikipedia.org/wiki/Segment_tree) data structure + * + * @details + * A segment tree, also known as a statistic tree, is a tree data structure used + * for storing information about intervals, or segments. Its classical version + * allows querying which of the stored segments contain a given point, but our + * modification allows us to perform (query) any binary operation on any range + * in the array in O(logN) time. Here, we have used addition (+). + * For range updates, we have used lazy propagation. + * + * * Space Complexity : O(NlogN) \n + * * Build Time Complexity : O(NlogN) \n + * * Query Time Complexity : O(logN) \n + * + * @author [Madhav Gaba](https://github.com/madhavgaba) + * @author [Soham Roy](https://github.com/sohamroy19) + */ + +#include /// for assert +#include /// for log2 +#include /// for IO operations +#include /// for std::vector + +/** + * @brief Constructs the initial segment tree + * + * @param arr input to construct the tree out of + * @param segtree the segment tree + * @param low inclusive lowest index of arr to begin at + * @param high inclusive highest index of arr to end at + * @param pos index of segtree to fill (eg. root node) + * @returns void + */ +void ConsTree(const std::vector &arr, std::vector *segtree, + uint64_t low, uint64_t high, uint64_t pos) { if (low == high) { - segtree[pos] = arr[low]; + (*segtree)[pos] = arr[low]; return; } - ll mid = (low + high) / 2; + + uint64_t mid = (low + high) / 2; ConsTree(arr, segtree, low, mid, 2 * pos + 1); ConsTree(arr, segtree, mid + 1, high, 2 * pos + 2); - segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2]; + (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2]; } -ll query(ll segtree[], ll lazy[], ll qlow, ll qhigh, ll low, ll high, ll pos) { - if (low > high) + +/** + * @brief Returns the sum of all elements in a range + * + * @param segtree the segment tree + * @param lazy for lazy propagation + * @param qlow lower index of the required query + * @param qhigh higher index of the required query + * @param low lower index of query for this function call + * @param high higher index of query for this function call + * @param pos index of segtree to consider (eg. root node) + * @return result of the range query for this function call + */ +int64_t query(std::vector *segtree, std::vector *lazy, + uint64_t qlow, uint64_t qhigh, uint64_t low, uint64_t high, + uint64_t pos) { + if (low > high || qlow > high || low > qhigh) { return 0; - if (qlow > high || qhigh < low) - return 0; - if (lazy[pos] != 0) { - segtree[pos] += lazy[pos] * (high - low + 1); - if (low != high) { - lazy[2 * pos + 1] += lazy[pos]; - lazy[2 * pos + 2] += lazy[pos]; - } - lazy[pos] = 0; } - if (qlow <= low && qhigh >= high) - return segtree[pos]; - ll mid = (low + high) / 2; + + if ((*lazy)[pos] != 0) { + (*segtree)[pos] += (*lazy)[pos] * (high - low + 1); + + if (low != high) { + (*lazy)[2 * pos + 1] += (*lazy)[pos]; + (*lazy)[2 * pos + 2] += (*lazy)[pos]; + } + (*lazy)[pos] = 0; + } + + if (qlow <= low && qhigh >= high) { + return (*segtree)[pos]; + } + + uint64_t mid = (low + high) / 2; + return query(segtree, lazy, qlow, qhigh, low, mid, 2 * pos + 1) + query(segtree, lazy, qlow, qhigh, mid + 1, high, 2 * pos + 2); } -void update(ll segtree[], ll lazy[], ll start, ll end, ll delta, ll low, - ll high, ll pos) { - if (low > high) + +/** + * @brief Updates a range of the segment tree + * + * @param segtree the segment tree + * @param lazy for lazy propagation + * @param start lower index of the required query + * @param end higher index of the required query + * @param delta integer to add to each element of the range + * @param low lower index of query for this function call + * @param high higher index of query for this function call + * @param pos index of segtree to consider (eg. root node) + * @returns void + */ +void update(std::vector *segtree, std::vector *lazy, + int64_t start, int64_t end, int64_t delta, uint64_t low, + uint64_t high, uint64_t pos) { + if (low > high) { return; - if (lazy[pos] != 0) { - segtree[pos] += lazy[pos] * (high - low + 1); - if (low != high) { - lazy[2 * pos + 1] += lazy[pos]; - lazy[2 * pos + 2] += lazy[pos]; - } - lazy[pos] = 0; } - if (start > high || end < low) + + if ((*lazy)[pos] != 0) { + (*segtree)[pos] += (*lazy)[pos] * (high - low + 1); + + if (low != high) { + (*lazy)[2 * pos + 1] += (*lazy)[pos]; + (*lazy)[2 * pos + 2] += (*lazy)[pos]; + } + (*lazy)[pos] = 0; + } + + if (start > high || end < low) { return; + } + if (start <= low && end >= high) { - segtree[pos] += delta * (high - low + 1); + (*segtree)[pos] += delta * (high - low + 1); + if (low != high) { - lazy[2 * pos + 1] += delta; - lazy[2 * pos + 2] += delta; + (*lazy)[2 * pos + 1] += delta; + (*lazy)[2 * pos + 2] += delta; } + return; } - ll mid = (low + high) / 2; + + uint64_t mid = (low + high) / 2; + update(segtree, lazy, start, end, delta, low, mid, 2 * pos + 1); update(segtree, lazy, start, end, delta, mid + 1, high, 2 * pos + 2); - segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2]; + (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2]; } + +/** + * @brief Self-test implementation + * + * @returns void + */ +static void test() { + int64_t max = static_cast(2 * pow(2, ceil(log2(7))) - 1); + assert(max == 15); + + std::vector arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max); + ConsTree(arr, &segtree, 0, 7 - 1, 0); + + assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 3 + 4 + 5 + 6); + + update(&segtree, &lazy, 2, 4, 1, 0, 7 - 1, 0); + assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 4 + 5 + 6 + 6); + + update(&segtree, &lazy, 0, 6, -2, 0, 7 - 1, 0); + assert(query(&segtree, &lazy, 0, 4, 0, 7 - 1, 0) == -1 + 0 + 2 + 3 + 4); +} + +/** + * @brief Main function + * + * @return 0 on exit + */ int main() { - ll n, c; - scanf("%lld %lld", &n, &c); - ll arr[n] = {0}, p, q, v, choice; - ll segtree[MAX], lazy[MAX] = {0}; - ConsTree(arr, segtree, 0, n - 1, 0); - while (c--) { - scanf("%lld", &choice); - if (choice == 0) { - scanf("%lld %lld %lld", &p, &q, &v); - update(segtree, lazy, p - 1, q - 1, v, 0, n - 1, 0); - } else { - scanf("%lld %lld", &p, &q); - printf("%lld\n", query(segtree, lazy, p - 1, q - 1, 0, n - 1, 0)); + test(); // run self-test implementations + + std::cout << "Enter number of elements: "; + + uint64_t n = 0; + std::cin >> n; + + uint64_t max = static_cast(2 * pow(2, ceil(log2(n))) - 1); + std::vector arr(n), lazy(max), segtree(max); + + int choice = 0; + std::cout << "\nDo you wish to enter each number?:\n" + "1: Yes\n" + "0: No (default initialize them to 0)\n"; + + std::cin >> choice; + if (choice == 1) { + std::cout << "Enter " << n << " numbers:\n"; + for (int i = 1; i <= n; i++) { + std::cout << i << ": "; + std::cin >> arr[i]; } } + + ConsTree(arr, &segtree, 0, n - 1, 0); + + do { + std::cout << "\nMake your choice:\n" + "1: Range update (input)\n" + "2: Range query (output)\n" + "0: Exit\n"; + std::cin >> choice; + + if (choice == 1) { + std::cout << "Enter 1-indexed lower bound, upper bound & value:\n"; + + uint64_t p = 1, q = 1, v = 0; + std::cin >> p >> q >> v; + update(&segtree, &lazy, p - 1, q - 1, v, 0, n - 1, 0); + } else if (choice == 2) { + std::cout << "Enter 1-indexed lower bound & upper bound:\n"; + + uint64_t p = 1, q = 1; + std::cin >> p >> q; + std::cout << query(&segtree, &lazy, p - 1, q - 1, 0, n - 1, 0); + std::cout << "\n"; + } + } while (choice > 0); + return 0; }