From 5ba8bc2c863b2df0de94d39648e959cf4cc0f90c Mon Sep 17 00:00:00 2001 From: GeorgianaK <52410645+GeorgianaK@users.noreply.github.com> Date: Tue, 25 May 2021 08:22:52 +0300 Subject: [PATCH 01/22] read violation resolved (#1496) --- .../circular_queue_using_linked_list.cpp | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/data_structures/circular_queue_using_linked_list.cpp b/data_structures/circular_queue_using_linked_list.cpp index 5d6484ce3..3d92b3b3e 100644 --- a/data_structures/circular_queue_using_linked_list.cpp +++ b/data_structures/circular_queue_using_linked_list.cpp @@ -2,34 +2,27 @@ struct node { int data; - struct node *next; + struct node* next; }; class Queue { - node *front; - node *rear; + node* front=nullptr; + node* rear=nullptr; - public: - Queue() { - front = NULL; - rear = NULL; - } +public: + Queue() = default; void createNode(int val) { - node *ptr; - node *nn; - nn = new node; - ptr = front; + auto* nn = new node; nn->data = val; - nn->next = NULL; + nn->next = nullptr; front = nn; rear = nn; } void enqueue(int val) { - if (front == NULL || rear == NULL) { + if (front == nullptr || rear == nullptr) { createNode(val); - } else { - node *ptr; - node *nn; - ptr = front; + } + else { + node* nn; nn = new node; nn->data = val; rear->next = nn; @@ -38,19 +31,23 @@ class Queue { } } void dequeue() { - node *n; + node* n; n = front; - front = front->next; - delete (n); + if (n) { + front = front->next; + delete n; + } } void traverse() { - node *ptr; + node* ptr; ptr = front; - do { - std::cout << ptr->data << " "; - ptr = ptr->next; - } while (ptr != rear->next); - std::cout << front->data << std::endl; + if (ptr) { + do { + std::cout << ptr->data << " "; + ptr = ptr->next; + } while (ptr != rear->next); + std::cout << front->data << std::endl; + } } }; int main(void) { From 17405a05ee9d0bc8ff14296aed1b9ce7c00f1e23 Mon Sep 17 00:00:00 2001 From: Mann Patel <46739555+manncodes@users.noreply.github.com> Date: Tue, 8 Jun 2021 01:54:49 +0530 Subject: [PATCH 02/22] feat: add spare table data structure (#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 * fixed author name suggested changes Co-authored-by: David Leal * fixed test() info to Doxygen standards. suggested changes Co-authored-by: David Leal * changed comment suggested changes Co-authored-by: David Leal * minor changes in file info suggested changes Co-authored-by: David Leal * minor changes in file info suggested changes Co-authored-by: David Leal * minor changes in file info suggested changes Co-authored-by: David Leal * changes in variable and struct descriptions * Update data_structures/sparse_table.cpp Co-authored-by: David Leal * Update data_structures/sparse_table.cpp Co-authored-by: David Leal * Update data_structures/sparse_table.cpp Co-authored-by: David Leal * changed int data type for non-negative numbers * changing datatypes of certain variables * Update data_structures/sparse_table.cpp Co-authored-by: David Leal * Update data_structures/sparse_table.cpp Co-authored-by: Ayaan Khan * clang-format and clang-tidy fixes for ddf777fc * minor changes * fixed comparison of integer of diff signedness * Update data_structures/sparse_table.cpp Co-authored-by: David Leal * 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 Co-authored-by: Ayaan Khan --- DIRECTORY.md | 1 + data_structures/sparse_table.cpp | 164 +++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 data_structures/sparse_table.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 178f809b2..ccbc5c68f 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -47,6 +47,7 @@ * [Queue Using Two Stacks](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/queue_using_two_stacks.cpp) * [Rb Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/rb_tree.cpp) * [Skip List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/skip_list.cpp) + * [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/sparse_table.cpp) * [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) diff --git a/data_structures/sparse_table.cpp b/data_structures/sparse_table.cpp new file mode 100644 index 000000000..b99616ae6 --- /dev/null +++ b/data_structures/sparse_table.cpp @@ -0,0 +1,164 @@ +/** + * @file + * @brief Implementation of [Sparse + * Table](https://brilliant.org/wiki/sparse-table/) for `min()` function. + * @author [Mann Patel](https://github.com/manncodes) + * @details + * Sparse Table is a data structure, that allows answering range queries. + * It can answer most range queries in O(logn), but its true power is answering + * range minimum queries (or equivalent range maximum queries). For those + * queries it can compute the answer in O(1) time. The only drawback of this + * data structure is, that it can only be used on immutable arrays. This means, + * that the array cannot be changed between two queries. + * + * If any element in the array changes, the complete data structure has to be + * recomputed. + * + * @todo make stress tests. + * + * @warning + * This sparse table is made for `min(a1,a2,...an)` duplicate invariant + * function. This implementation can be changed to other functions like + * `gcd()`, `lcm()`, and `max()` by changing a few lines of code. + */ + +#include /// for std::array +#include /// for assert +#include /// for IO operations + +/** + * @namespace data_structures + * @brief Data Structures algorithms + */ +namespace data_structures { + +/** + * @namespace sparse_table + * @brief Functions for Implementation of [Sparse + * Table](https://brilliant.org/wiki/sparse-table/) + */ +namespace sparse_table { + +/** + * @brief A struct to represent sparse table for `min()` as their invariant + * function, for the given array `A`. The answer to queries are stored in the + * array ST. + */ +constexpr uint32_t N = 12345; ///< the maximum size of the array. +constexpr uint8_t M = 14; ///< ceil(log2(N)). + +struct Sparse_table { + size_t n = 0; ///< size of input array. + + /** @warning check if `N` is not less than `n`. if so, manually increase the + * value of N */ + + std::array A = {}; ///< input array to perform RMQ. + std::array, M> + ST{}; ///< the sparse table storing `min()` values for given interval. + std::array LOG = {}; ///< where floor(log2(i)) are precomputed. + + /** + * @brief Builds the sparse table for computing min/max/gcd/lcm/...etc + * for any contiguous sub-segment of the array.This is an example of + * computing the index of the minimum value. + * @return void + * @complexity: O(n.log(n)) + */ + void buildST() { + LOG[0] = -1; + + for (size_t i = 0; i < n; ++i) { + ST[0][i] = static_cast(i); + LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)` + } + + for (size_t j = 1; static_cast(1 << j) <= n; ++j) { + for (size_t i = 0; static_cast(i + (1 << j)) <= n; ++i) { + /** + * @note notice how we deal with the range of length `pow(2,i)`, + * and we can reuse the computation that we did for the range of + * length `pow(2,i-1)`. + * + * So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]). + * @example ST[2][3] = min(ST[1][3], ST[1][5]) + */ + + int64_t x = ST[j - 1][i]; ///< represents minimum value over + ///< the range [j,i] + int64_t y = + ST[j - 1] + [i + (1 << (j - 1))]; ///< represents minimum value over + ///< the range [j,i + pow(2,j-1)] + + ST[j][i] = + (A[x] <= A[y] ? x : y); ///< represents minimum value over + ///< the range [j,i] + } + } + } + + /** + * @brief Queries the sparse table for the value of the interval [l, r] + * (i.e. from l to r inclusive). + * @param l the left index of the range (inclusive). + * @param r the right index of the range (inclusive). + * @return the computed value of the given interval. + * @complexity: O(1) + */ + int64_t query(int64_t l, int64_t r) { + int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r] + int64_t x = ST[g][l]; ///< represents minimum value over the range + ///< [g,l] + int64_t y = + ST[g][r - (1 << g) + 1]; ///< represents minimum value over the + ///< range [g, r - pow(2,g) + 1] + + return (A[x] <= A[y] ? x : y); ///< represents minimum value over + ///< the whole range [l,r] + } +}; +} // namespace sparse_table +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + /* We take an array as an input on which we need to perform the ranged + * minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query). + */ + std::array testcase = { + 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10}; ///< array on which RMQ will be performed. + size_t testcase_size = + sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array + + data_structures::sparse_table::Sparse_table + st{}; ///< declaring sparse tree + + std::copy(std::begin(testcase), std::end(testcase), + std::begin(st.A)); ///< copying array to the struct + st.n = testcase_size; ///< passing the array's size to the struct + + st.buildST(); ///< precomputing sparse tree + + // pass queries of the form: [l,r] + assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9 + assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6 + assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8 + + std::cout << "Self-test implementations passed!" << std::endl; +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // run self-test implementations + return 0; +} From 554919d9f59190f720d4ccae10da4eefb4b49eb2 Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 18 Jun 2021 14:17:31 -0500 Subject: [PATCH 03/22] [feat/fix/docs]: Improve the `dynamic_programming/longest_increasing_subsequence.cpp` file (#1504) * [feat/fix/docs]: Improve the `dynamic_programming/longest_increasing_subsequence.cpp` file * [test/feat]: Add self-test implementations and... ...namespace (`dynamic_programming`). Thanks to @manncodes for the idea and help! Co-authored-by: Mann Patel * clang-format and clang-tidy fixes for 7d4562d6 Co-authored-by: Mann Patel Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- .../longest_increasing_subsequence.cpp | 96 ++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/dynamic_programming/longest_increasing_subsequence.cpp b/dynamic_programming/longest_increasing_subsequence.cpp index b6a798aa0..a93c139c4 100644 --- a/dynamic_programming/longest_increasing_subsequence.cpp +++ b/dynamic_programming/longest_increasing_subsequence.cpp @@ -1,32 +1,98 @@ -// Program to calculate length of longest increasing subsequence in an array -#include -using namespace std; -int LIS(int a[], int n) { - int lis[n]; +/** + * @file + * @brief Calculate the length of the [longest increasing + * subsequence](https://en.wikipedia.org/wiki/Longest_increasing_subsequence) in + * an array + * + * @details + * In computer science, the longest increasing subsequence problem is to find a + * subsequence of a given sequence in which the subsequence's elements are in + * sorted order, lowest to highest, and in which the subsequence is as long as + * possible. This subsequence is not necessarily contiguous, or unique. Longest + * increasing subsequences are studied in the context of various disciplines + * related to mathematics, including algorithmics, random matrix theory, + * representation theory, and physics. The longest increasing subsequence + * problem is solvable in time O(n log n), where n denotes the length of the + * input sequence. + * + * @author [Krishna Vedala](https://github.com/kvedala) + * @author [David Leal](https://github.com/Panquesito7) + */ + +#include /// for assert +#include /// for std::max +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace dynamic_programming + * @brief Dynamic Programming algorithms + */ +namespace dynamic_programming { +/** + * @brief Calculate the longest increasing subsequence for the specified numbers + * @param a the array used to calculate the longest increasing subsequence + * @param n the size used for the arrays + * @returns the length of the longest increasing + * subsequence in the `a` array of size `n` + */ +uint64_t LIS(const std::vector &a, const uint32_t &n) { + std::vector lis(n); for (int i = 0; i < n; ++i) { lis[i] = 1; } for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { - if (a[i] > a[j] && lis[i] < lis[j] + 1) + if (a[i] > a[j] && lis[i] < lis[j] + 1) { lis[i] = lis[j] + 1; + } } } int res = 0; for (int i = 0; i < n; ++i) { - res = max(res, lis[i]); + res = std::max(res, lis[i]); } return res; } +} // namespace dynamic_programming + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + std::vector a = {15, 21, 2, 3, 4, 5, 8, 4, 1, 1}; + uint32_t n = a.size(); + + uint32_t result = dynamic_programming::LIS(a, n); + assert(result == + 5); ///< The longest increasing subsequence is `{2,3,4,5,8}` + + std::cout << "Self-test implementations passed!" << std::endl; +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ int main(int argc, char const *argv[]) { - int n; - cout << "Enter size of array: "; - cin >> n; - int a[n]; - cout << "Enter array elements: "; + uint32_t n = 0; + + std::cout << "Enter size of array: "; + std::cin >> n; + + std::vector a(n); + + std::cout << "Enter array elements: "; for (int i = 0; i < n; ++i) { - cin >> a[i]; + std::cin >> a[i]; } - cout << LIS(a, n) << endl; + + std::cout << "\nThe result is: " << dynamic_programming::LIS(a, n) + << std::endl; + test(); // run self-test implementations + return 0; -} \ No newline at end of file +} From d54afc520f787fab5ba651ee06b7f00bf200a8b4 Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 18 Jun 2021 14:55:52 -0500 Subject: [PATCH 04/22] [feat/fix]: Improve the contributing guidelines (#1503) * [feat/fix]: Improve the contributing guidelines Mostly fix grammar, spelling errors, typos, and improves wording. * [docs]: Apply suggestions from code review * [feat/fix]: Minor improvements/fixes Co-authored-by: Ayaan Khan --- CONTRIBUTING.md | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e04cee749..d5bc3132e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,54 +2,54 @@ ## Before contributing -Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-Plus)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C-Plus-Plus/issues/new/choose) and clearly state your concerns. +Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-Plus)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C-Plus-Plus/issues/new/choose) or ask in our [Discord server](https://discord.gg/c7MnfGFGa6), and clearly state your concerns. ## Contributing ### Contributor -We are very happy that you consider implementing algorithms and data structures for others! This repository is referred to and used by learners from around the globe. Being one of our contributors, you agree and confirm that: +Being a contributor at The Algorithms, we request you to follow the points mentioned below: - You did your own work. - No plagiarism allowed. Any plagiarized work will not be merged. -- Your work will be distributed under [MIT License](License) once your pull request has been merged. -- You submitted work fulfils or mostly fulfils our styles and standards. +- Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/C-Plus-Plus/blob/master/LICENSE) once your pull request has been merged. +- Please follow the repository guidelines and standards mentioned below. -**New implementation** New implementation are welcome! +**New implementation** New implementations are welcome! -**Improving comments** and **adding tests** to existing algorithms are much appreciated. +You can add new algorithms or data structures which are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs or in any other resonable sense) -**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request and it will be evaluated by project maintainers. +**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. ### Making Changes #### Code - Please use the directory structure of the repository. -- File extension for code should be `*.hpp`, `*.h` or `*.cpp`. -- Don't use **bits/stdc++.h** because this is quite Linux specific and slows down the compilation process. -- Organize your code using **`struct`**, **`class`** and/or **`namespace`** keywords +- Make sure the file extensions should be `*.hpp`, `*.h` or `*.cpp`. +- Don't use **`bits/stdc++.h`** because this is quite Linux-specific and slows down the compilation process. +- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords - If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines). - You can suggest reasonable changes to existing algorithms. - Strictly use snake_case (underscore_separated) in filenames. - If you have added or modified code, please make sure the code compiles before submitting. -- Our automated testing runs [__CMake__](https://cmake.org/) on all pull requests so please be sure that your code passes before submitting. -- Please conform to [doxygen](https://www.doxygen.nl/manual/docblocks.html) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on website. -- **Be consistent in use of these guidelines.** +- Our automated testing runs [__CMake__](https://cmake.org/) on all the pull requests, so please be sure that your code passes before submitting. +- Please conform to [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on the website. +- **Be consistent in the use of these guidelines.** #### Documentation -- Make sure you put useful comments in your code. Do not comment things that are obvious. +- Make sure you put useful comments in your code. Do not comment on obvious things. - Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure. If you want to create a new directory, then please check if a similar category has been recently suggested or created by other pull requests. -- If you have modified/added documentation, please ensure that your language is concise and contains no grammar errors. -- Do not update [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md) along with other changes. First create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md). -- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C-Plus-Plus). Please ensure the code is documented in this structure. Sample implementation is given below. +- If you have modified/added documentation, please ensure that your language is concise and must not contain grammatical errors. +- Do not update [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md) along with other changes. First, create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md). +- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C-Plus-Plus). Please ensure the code is documented in this structure. A sample implementation is given below. #### Test -- Make sure to add examples and test cases in your main() function. -- If you find any algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. -- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with expected output. Use `assert()` function to confirm that the tests will pass. Requires including the `cassert` header. +- Make sure to add examples and test cases in your `main()` function. +- If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. +- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `cassert` header. #### Typical structure of a program @@ -130,7 +130,7 @@ int main(int argc, char *argv[]) { #### New File Name guidelines -- Use lowercase words with ``"_"`` as separator +- Use lowercase words with ``"_"`` as a separator - For instance ```markdown @@ -139,8 +139,8 @@ my_new_cpp_class.cpp is correct format ``` - It will be used to dynamically create a directory of files and implementation. -- File name validation will run on docker to ensure the validity. -- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example, if `median_search.cpp` already exists in the `search` folder and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`. +- File name validation will run on docker to ensure validity. +- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `median_search.cpp` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`. #### New Directory guidelines @@ -158,7 +158,7 @@ some_new_fancy_category is correct #### Commit Guidelines -- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilt across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected. +- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilled across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected. ```bash git add file_xyz.cpp @@ -216,14 +216,14 @@ clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp -- #### GitHub Actions - Enable GitHub Actions on your fork of the repository. -After enabling it will execute `clang-tidy` and `clang-format` after every push (not a commit). +After enabling, it will execute `clang-tidy` and `clang-format` after every push (not a commit). - Click on the tab "Actions", then click on the big green button to enable it. ![GitHub Actions](https://user-images.githubusercontent.com/51391473/94609466-6e925100-0264-11eb-9d6f-3706190eab2b.png) - The result can create another commit if the actions made any changes on your behalf. - Hence, it is better to wait and check the results of GitHub Actions after every push. -- Run `git pull` in your local clone if these actions made many changes in order to avoid merge conflicts. +- Run `git pull` in your local clone if these actions made many changes to avoid merge conflicts. Most importantly, From 47c84137eec683790faa494ac0068d7c9f88f8ff Mon Sep 17 00:00:00 2001 From: Motasim <44056349+motasimmakki@users.noreply.github.com> Date: Tue, 6 Jul 2021 06:02:41 +0530 Subject: [PATCH 05/22] feat: Added implementation of iterative version of tree traversals. (#1506) * feat: Added iterative version of tree traversals. Here is the implementation of the iterative version of the Preorder, Postorder, and the Inorder traversal of given tree. . Time Complexity: O(n), where 'n' is the total number of nodes in a tree. * updating DIRECTORY.md * fixed: function descriptions, namespace declaration, and included separate libraries. * fixed: added range bases for loops. * style: proper indentation Co-authored-by: David Leal * style: proper indentation Co-authored-by: David Leal * style: proper indentation Co-authored-by: David Leal * fix: C style NULL to nullptr Co-authored-by: David Leal * docs: spell correction Co-authored-by: David Leal * style: formatted comments. * fixes: static_cast, if and for statement braces * style: modified pointer declaration. * fixes: removed use of typedef, renamed BT to Node * Fix `clang-tidy` warnings * fix: Try to fix `clang-tidy` warnings this time * docs: Proper function description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * fix: Class based approach * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * fix: Initialized data variable Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description Co-authored-by: David Leal * docs: Removed unnecessary comment Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description * docs: Proper variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Included variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Included variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * docs: Proper variables description Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> * fixes: Self-test implementation and namespace * docs: Documentation improvements * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper indentation Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Improved function description * docs: Proper formatted description Co-authored-by: David Leal * test: Added test cases for negative values * docs: Proper description Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper formatted comment Co-authored-by: David Leal * docs: Proper function description Co-authored-by: David Leal * docs: Proper formatted description Co-authored-by: David Leal * docs: Proper description Co-authored-by: David Leal * docs: Proper description Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Mann Patel <46739555+manncodes@users.noreply.github.com> --- DIRECTORY.md | 1 + others/iterative_tree_traversals.cpp | 362 +++++++++++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 others/iterative_tree_traversals.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index ccbc5c68f..f735080e1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -229,6 +229,7 @@ * [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp) * [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_integer_input.cpp) * [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/happy_number.cpp) + * [Iterative Tree Traversals](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/iterative_tree_traversals.cpp) * [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/matrix_exponentiation.cpp) * [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/palindrome_of_number.cpp) * [Paranthesis Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/paranthesis_matching.cpp) diff --git a/others/iterative_tree_traversals.cpp b/others/iterative_tree_traversals.cpp new file mode 100644 index 000000000..6d0e7dc2e --- /dev/null +++ b/others/iterative_tree_traversals.cpp @@ -0,0 +1,362 @@ +/** + * @file + * @brief Iterative version of Preorder, Postorder, and preorder [Traversal of the Tree] + * (https://en.wikipedia.org/wiki/Tree_traversal) + * @author [Motasim](https://github.com/motasimmakki) + * @details + * + * ### Iterative Preorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current, and pop and elemnt from the stack. + * Store the data of current into the result array, and start traversing from it. + * Push both the child node of the current node into the stack, first right child then left child. + * Repeat the same set of steps untill the Stack becomes empty. + * And return the result array as the preorder traversal of a tree. + * + * ### Iterative Postorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current, and pop and elemnt from the stack. + * Store the data of current into the result array, and start traversing from it. + * Push both the child node of the current node into the stack, first left child then right child. + * Repeat the same set of steps untill the Stack becomes empty. + * Now reverse the result array and then return it to the calling function as a postorder traversal of a tree. + * + * ### Iterative Inorder Traversal of a tree + * Create a Stack that will store the Node of Tree. + * Push the root node into the stack. + * Save the root into the variabe named as current. + * Now iterate and take the current to the extreme left of the tree by traversing only to its left. + * Pop the elemnt from the stack and assign it to the current. + * Store the data of current into the result array. + * Repeat the same set of steps until the Stack becomes empty or the current becomes NULL. + * And return the result array as the inorder traversal of a tree. + */ +#include /// for I/O operations +#include /// for `stack` +#include /// for `vector` +#include /// for `reverse` +#include /// for `assert` + +/** + * @namespace others + * @brief Other algorithms + */ +namespace others { +/** + * @namespace iterative_tree_traversals + * @brief Functions for the [Traversal of the Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm + */ +namespace iterative_tree_traversals { +/** + * @brief defines the structure of a node of the tree + */ +struct Node { + int64_t data = 0; ///< The value/key of the node. + struct Node *left; ///< struct pointer to left subtree. + struct Node *right; ///< struct pointer to right subtree. +}; + +/** + * @brief defines the functions associated with the binary tree + */ +class BinaryTree { + public: + Node *createNewNode(int64_t); ///< function that will create new node for insertion. + std::vector preOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its preorder traversal. + std::vector postOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its postorder traversal. + std::vector inOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its inorder traversal. +}; + +/** + * @brief will allocate the memory for a node and, along the data and return the node. + * @param data value that a particular node will contain. + * @return pointer to the newly created node with assigned data. + */ +Node * BinaryTree::createNewNode(int64_t data) { + Node *node = new Node(); + node->data = data; + node->left = node->right = nullptr; + return node; +} + +/** + * @brief preOrderIterative() function that will perform the preorder traversal iteratively, + * and return the result array that contain the preorder traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the preorder traversal of a tree + */ +std::vector BinaryTree::preOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< list of values, sorted in pre-order. + + stack.push(root); + + while(!stack.empty()) { + result.push_back(stack.top()->data); + Node *current = stack.top(); + stack.pop(); + + if(current->right) { + stack.push(current->right); + } + if(current->left) { + stack.push(current->left); + } + } + + return result; +} + +/** + * @brief postOrderIterative() function that will perform the postorder traversal iteratively, + * and return the result array that contain the postorder traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the postorder traversal of a tree + */ +std::vector BinaryTree::postOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< List of values, sorted in post-order. + + stack.push(root); + + while(!stack.empty()) { + result.push_back(stack.top()->data); + Node *current = stack.top(); + stack.pop(); + + if(current->left) { + stack.push(current->left); + } + if(current->right) { + stack.push(current->right); + } + } + + reverse(result.begin(), result.end()); + + return result; +} + +/** + * @brief inOrderIterative() function that will perform the inorder traversal iteratively, + * and return the result array that contain the inorder traversal of a tree. + * @param root head/root node of a tree + * @return result that is containing the inorder traversal of a tree + */ +std::vector BinaryTree::inOrderIterative(Node *root) { + std::stack stack; ///< is used to find and traverse the child nodes. + std::vector result; ///< List of values, sorted in in-order. + + Node *current = root; + + while(!stack.empty() || current) { + while(current) { + stack.push(current); + current = current->left; + } + current = stack.top(); + stack.pop(); + result.push_back(current->data); + current = current->right; + } + return result; +} +} // namespace iterative_tree_traversals +} // namespace others + +/** + * @brief Test the computed preorder with the actual preorder. + * @param binaryTree instance of the BinaryTree class + * @param root head/root node of a tree + */ +static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{1, 2, 4, 5, 3}; + std::vector result; ///< result stores the preorder traversal of the binary tree + + // Calling preOrderIterative() function by passing a root node, + // and storing the preorder traversal in result. + result = binaryTree.preOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing preorder. + std::cout<< "\nPreOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed postorder with the actual postorder. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{4, 5, 2, 3, 1}; + std::vector result; ///< result stores the postorder traversal of the binary tree. + + // Calling postOrderIterative() function by passing a root node, + // and storing the postorder traversal in result. + result = binaryTree.postOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing postorder. + std::cout<< "\nPostOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed inorder with the actual inorder. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{4, 2, 5, 1, 3}; + std::vector result; ///< result stores the inorder traversal of the binary tree. + + // Calling inOrderIterative() function by passing a root node, + // and storing the inorder traversal in result. + result = binaryTree.inOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing inorder. + std::cout<< "\nInOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed preorder with the actual preorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-1, -2, -4, -5, -3}; + std::vector result; ///< result stores the preorder traversal of the binary tree + + // Calling preOrderIterative() function by passing a root node, + // and storing the preorder traversal in result. + result = binaryTree.preOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing preorder. + std::cout<< "\nPreOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed postorder with the actual postorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-4, -5, -2, -3, -1}; + std::vector result; ///< result stores the postorder traversal of the binary tree. + + // Calling postOrderIterative() function by passing a root node, + // and storing the postorder traversal in result. + result = binaryTree.postOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing postorder. + std::cout<< "\nPostOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Test the computed inorder with the actual inorder on negative value. + * @param binaryTree instance of BinaryTree class + * @param root head/root node of a tree + */ +static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ + std::vector actual_result{-4, -2, -5, -1, -3}; + std::vector result; ///< result stores the inorder traversal of the binary tree. + + // Calling inOrderIterative() function by passing a root node, + // and storing the inorder traversal in result. + result = binaryTree.inOrderIterative(root); + + // Self-testing the result using `assert` + for(int i = 0; i < result.size(); i++) + assert(actual_result[i] == result[i]); + + // Printing the result storing inorder. + std::cout<< "\nInOrder Traversal Is : "<< std::endl; + for(auto i: result) { + std::cout<< i<< " "; + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + // Creating a tree with the following structure, + /* + 1 + / \ + 2 3 + / \ + 4 5 + */ + + others::iterative_tree_traversals::BinaryTree binaryTree; ///< instace of BinaryTree, used to access its members functions. + others::iterative_tree_traversals::Node *root = binaryTree.createNewNode(1); + root->left = binaryTree.createNewNode(2); + root->right = binaryTree.createNewNode(3); + root->left->left = binaryTree.createNewNode(4); + root->left->right = binaryTree.createNewNode(5); + + std::cout<< "\n| Tests for positive data value |"<< std::endl; + test1(binaryTree, root); // run preorder-iterative test + std::cout<< "\nPre-order test Passed!"<< std::endl; + + test2(binaryTree, root); // run postorder-iterative test + std::cout<< "\nPost-order test Passed!"<< std::endl; + + test3(binaryTree, root); // run inorder-iterative test + std::cout<< "\nIn-order test Passed!"<< std::endl; + + // Modifying tree for negative values. + root->data = -1; + root->left->data = -2; + root->right->data = -3; + root->left->left->data = -4; + root->left->right->data = -5; + + std::cout<< "\n| Tests for negative data values |"<< std::endl; + test4(binaryTree, root); // run preorder-iterative test on negative values + std::cout<< "\nPre-order test on-negative value Passed!"<< std::endl; + + test5(binaryTree, root); // run postorder-iterative test on negative values + std::cout<< "\nPost-order test on-negative value Passed!"<< std::endl; + + test6(binaryTree, root); // run inorder-iterative test on negative values + std::cout<< "\nIn-order test on-negative value Passed!"<< std::endl; + + return 0; +} From 0c5c096991f29365fbce1c0ed91937887a94793d Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 5 Jul 2021 22:02:33 -0500 Subject: [PATCH 06/22] [feat/fix]: Improve the contributing guidelines... (#1522) ...and add the `CodingGuidelines.md` file, taken and edited from the [C](https://github.com/TheAlgorithms/C) repository. --- CONTRIBUTING.md | 28 ++++++++++++++++------------ CodingGuidelines.md | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 CodingGuidelines.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5bc3132e..72014433d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,10 @@ Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-P ## Contributing +### Maintainer/reviewer + +**Please check the [reviewer code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/REVIEWER_CODE.md) file for maintainers and reviewers.** + ### Contributor Being a contributor at The Algorithms, we request you to follow the points mentioned below: @@ -49,7 +53,7 @@ You can add new algorithms or data structures which are **not present in the rep - Make sure to add examples and test cases in your `main()` function. - If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. -- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `cassert` header. +- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `cassert` library. #### Typical structure of a program @@ -58,15 +62,15 @@ You can add new algorithms or data structures which are **not present in the rep * @file * @brief Add one line description here * @details - * This is a multi line + * This is a multi-line * description containing links, references, - * math equations, etc + * math equations, etc. * @author [Name](https://github.com/handle) * @see related_file.cpp, another_file.cpp */ -#include -#include +#include /// for assert +#include /// for `some function here` /** * @namespace @@ -74,7 +78,7 @@ You can add new algorithms or data structures which are **not present in the rep namespace name { /** - * Class documentation + * @brief Class documentation */ class class_name { private: @@ -86,7 +90,7 @@ class class_name { } /** - * Function documentation + * @brief Function documentation * @tparam T this is a one-line info about T * @param param1 on-line info about param1 * @param param2 on-line info about param2 @@ -105,7 +109,7 @@ bool func(int param1, T param2) { } // namespace name /** - * @brief Test implementations + * @brief Self-test implementations * @returns void */ static void test() { @@ -122,7 +126,7 @@ static void test() { * @returns 0 on exit */ int main(int argc, char *argv[]) { - test(); // execute the tests + test(); // run self-test implementations // code here return 0; } @@ -139,7 +143,7 @@ my_new_cpp_class.cpp is correct format ``` - It will be used to dynamically create a directory of files and implementation. -- File name validation will run on docker to ensure validity. +- File name validation will run on Docker to ensure validity. - If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `median_search.cpp` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`. #### New Directory guidelines @@ -196,7 +200,7 @@ cmake -B build -S . #### Static Code Analyzer -We use [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) as a static code analyzer with a configuration in [.clang-tidy](.clang-tidy). +We use [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) as a static code analyzer with a configuration in [`.clang-tidy`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/.clang-tidy). ```bash clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp -- @@ -204,7 +208,7 @@ clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp -- #### Code Formatter -[__clang-format__](https://clang.llvm.org/docs/ClangFormat.html) is used for code forrmating. +[`__clang-format__`](https://clang.llvm.org/docs/ClangFormat.html) is used for code forrmating. - Installation (only needs to be installed once.) - Mac (using home-brew): `brew install clang-format` diff --git a/CodingGuidelines.md b/CodingGuidelines.md new file mode 100644 index 000000000..da38708b5 --- /dev/null +++ b/CodingGuidelines.md @@ -0,0 +1,18 @@ +# Code style convention + +Please orient on this guide before you sent a pull request. + +--- + +## User-interface + +Please write a simple user interface for your programs. Not a blinking cursor! +What does the program do? +What want the program an user informations? + +--- + +## Code style conventions + +See [here](https://users.ece.cmu.edu/~eno/coding/CppCodingStandard.html) +Don't push all code in one line! From 60ee52fd6a701352ae71a985bfa10614429d7cf2 Mon Sep 17 00:00:00 2001 From: Nitin Sharma <32377892+foo290@users.noreply.github.com> Date: Tue, 6 Jul 2021 22:49:27 +0530 Subject: [PATCH 07/22] feat: add random pivot quick sort algorithm (#1510) * feat: add random pivot quick sort algorithm, test cases included * updating DIRECTORY.md * docs: add proper docs for random pivot quick sort algorithm, code reformatted. * fix: copy constructor bug fixed for TestCase class for random pivot quick sort algo * docs and code reformatted according to standards * c-style array declarations removed * added minor suggestion in docs * resource link added in docs * docs formatted * test function's docs added, using stl function for swap * generator function migrated to namespace * Update sorting/random_pivot_quick_sort.cpp Co-authored-by: David Leal * Update sorting/random_pivot_quick_sort.cpp Co-authored-by: David Leal * Update sorting/random_pivot_quick_sort.cpp Co-authored-by: David Leal * docs fixed sorting/random pivot quick sort * Apply suggestions from code review Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + sorting/random_pivot_quick_sort.cpp | 309 ++++++++++++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 sorting/random_pivot_quick_sort.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index f735080e1..38e65a8a6 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -298,6 +298,7 @@ * [Quick Sort 3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort_3.cpp) * [Radix Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort.cpp) * [Radix Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort2.cpp) + * [Random Pivot Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/random_pivot_quick_sort.cpp) * [Recursive Bubble Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/recursive_bubble_sort.cpp) * [Selection Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort.cpp) * [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort.cpp) diff --git a/sorting/random_pivot_quick_sort.cpp b/sorting/random_pivot_quick_sort.cpp new file mode 100644 index 000000000..97892368f --- /dev/null +++ b/sorting/random_pivot_quick_sort.cpp @@ -0,0 +1,309 @@ +/** + * @file + * @brief Implementation of the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) algorithm. + * @details + * * A random pivot quick sort algorithm is pretty much same as quick sort with a difference of having a logic of + * selecting next pivot element from the input array. + * * Where in quick sort is fast, but still can give you the time complexity of O(n^2) in worst case. + * * To avoid hitting the time complexity of O(n^2), we use the logic of randomize the selection process of pivot + * element. + * + * ### Logic + * * The logic is pretty simple, the only change is in the partitioning algorithm, which is selecting the + * pivot element. + * * Instead of selecting the last or the first element from array for pivot we use a random index to select + * pivot element. + * * This avoids hitting the O(n^2) time complexity in practical use cases. + * + * ### Partition Logic + * * Partitions are done such as numbers lower than the "pivot" element is arranged on the left side of the "pivot", + * and number larger than the "pivot" element are arranged on the right part of the array. + * + * ### Algorithm + * * Select the pivot element randomly using getRandomIndex() function from this namespace. + * * Initialize the pInd (partition index) from the start of the array. + * * Loop through the array from start to less than end. (from start to < end). + * (Inside the loop) :- + * * Check if the current element (arr[i]) is less than the pivot element in each iteration. + * * If current element in the iteration is less than the pivot element, + * then swap the elements at current index (i) and partition index (pInd) and increment the partition index by one. + * * At the end of the loop, swap the pivot element with partition index element. + * * Return the partition index from the function. + * + * @author [Nitin Sharma](https://github.com/foo290) + */ + +#include /// for IO operations +#include /// for initializing random number generator +#include /// for assert +#include /// for std::is_sorted(), std::swap() +#include /// for std::array +#include /// for returning multiple values form a function at once + +/** + * @namespace sorting + * @brief Sorting algorithms + */ +namespace sorting { +/** + * @brief Functions for the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) implementation + * @namespace random_pivot_quick_sort + */ + namespace random_pivot_quick_sort { + /** + * @brief Utility function to print the array + * @tparam T size of the array + * @param arr array used to print its content + * @returns void + * */ + template + void showArray(std::array arr) { + for (int64_t i = 0; i < arr.size(); i++) { + std::cout << arr[i] << " "; + } + std::cout << std::endl; + } + + /** + * @brief Takes the start and end indices of an array and returns a random int64_teger between the range of those two + * for selecting pivot element. + * + * @param start The starting index. + * @param end The ending index. + * @returns int64_t A random number between start and end index. + * */ + int64_t getRandomIndex(int64_t start, int64_t end) { + srand(time(nullptr)); // Initialize random number generator. + int64_t randomPivotIndex = start + rand() % (end - start + 1); + return randomPivotIndex; + } + + /** + * @brief A partition function which handles the partition logic of quick sort. + * @tparam size size of the array to be passed as argument. + * @param start The start index of the passed array + * @param end The ending index of the passed array + * @returns std::tuple> A tuple of pivot index and pivot sorted array. + */ + template + std::tuple> partition(std::array arr, int64_t start, int64_t end) { + + int64_t pivot = arr[end]; // Randomly selected element will be here from caller function (quickSortRP()). + int64_t pInd = start; + + for (int64_t i = start; i < end; i++) { + if (arr[i] <= pivot) { + std::swap(arr[i], arr[pInd]); // swapping the elements from current index to pInd. + pInd++; + } + } + std::swap(arr[pInd], arr[end]); // swapping the pivot element to its sorted position + return std::make_tuple(pInd, arr); + } + + /** + * @brief Random pivot quick sort function. This function is the starting point of the algorithm. + * @tparam size size of the array to be passed as argument. + * @param start The start index of the passed array + * @param end The ending index of the passed array + * @returns std::array A fully sorted array in ascending order. + */ + template + std::array quickSortRP(std::array arr, int64_t start, int64_t end) { + if (start < end) { + + int64_t randomIndex = getRandomIndex(start, end); + + // switching the pivot with right most bound. + std::swap(arr[end], arr[randomIndex]); + + int64_t pivotIndex = 0; + // getting pivot index and pivot sorted array. + std::tie(pivotIndex, arr) = partition(arr, start, end); + + // Recursively calling + std::array rightSortingLeft = quickSortRP(arr, start, pivotIndex - 1); + std::array full_sorted = quickSortRP(rightSortingLeft, pivotIndex + 1, end); + arr = full_sorted; + } + return arr; + } + + /** + * @brief A function utility to generate unsorted array of given size and range. + * @tparam size Size of the output array. + * @param from Stating of the range. + * @param to Ending of the range. + * @returns std::array Unsorted array of specified size. + * */ + template + std::array generateUnsortedArray(int64_t from, int64_t to) { + srand(time(nullptr)); + std::array unsortedArray{}; + assert(from < to); + int64_t i = 0; + while (i < size) { + int64_t randomNum = from + rand() % (to - from + 1); + if (randomNum) { + unsortedArray[i] = randomNum; + i++; + } + } + return unsortedArray; + } + +} // namespace random_pivot_quick_sort +} // namespace sorting + +/** + * @brief a class containing the necessary test cases + */ +class TestCases { +private: + /** + * @brief A function to print64_t given message on console. + * @tparam T Type of the given message. + * @returns void + * */ + template + void log(T msg) { + // It's just to avoid writing cout and endl + std::cout << "[TESTS] : ---> " << msg << std::endl; + } + +public: + /** + * @brief Executes test cases + * @returns void + * */ + void runTests() { + log("Running Tests..."); + + testCase_1(); + testCase_2(); + testCase_3(); + + log("Test Cases over!"); + std::cout << std::endl; + } + + /** + * @brief A test case with single input + * @returns void + * */ + void testCase_1() { + const int64_t inputSize = 1; + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("This is test case 1 for Random Pivot Quick Sort Algorithm : "); + log("Description:"); + log(" EDGE CASE : Only contains one element"); + std::array unsorted_arr{2}; + + int64_t start = 0; + int64_t end = unsorted_arr.size() - 1; // length - 1 + + log("Running algorithm of data of length 50 ..."); + std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( + unsorted_arr, start, end + ); + log("Algorithm finished!"); + + log("Checking assert expression..."); + assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end())); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 1 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } + + /** + * @brief A test case with input array of length 500 + * @returns void + * */ + void testCase_2() { + const int64_t inputSize = 500; + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("Description:"); + log(" BIG INPUT : Contains 500 elements and repeated elements"); + log("This is test case 2 for Random Pivot Quick Sort Algorithm : "); + std::array unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray(1, 10000); + + int64_t start = 0; + int64_t end = unsorted_arr.size() - 1; // length - 1 + + log("Running algorithm of data of length 500 ..."); + std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( + unsorted_arr, start, end + ); + log("Algorithm finished!"); + + log("Checking assert expression..."); + assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end())); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 2 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } + + /** + * @brief A test case with array of length 1000. + * @returns void + * */ + void testCase_3() { + const int64_t inputSize = 1000; + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("This is test case 3 for Random Pivot Quick Sort Algorithm : "); + log("Description:"); + log(" LARGE INPUT : Contains 1000 elements and repeated elements"); + std::array unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray(1, 10000); + + int64_t start = 0; + int64_t end = unsorted_arr.size() - 1; // length - 1 + + log("Running algorithm..."); + std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( + unsorted_arr, start, end + ); + log("Algorithm finished!"); + + log("Checking assert expression..."); + assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end())); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 3 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } +}; + + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + TestCases tc = TestCases(); + tc.runTests(); +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // Executes various test cases. + + const int64_t inputSize = 10; + std::array unsorted_array = sorting::random_pivot_quick_sort::generateUnsortedArray(50, 1000); + std::cout << "Unsorted array is : " << std::endl; + sorting::random_pivot_quick_sort::showArray(unsorted_array); + + std::array sorted_array = sorting::random_pivot_quick_sort::quickSortRP( + unsorted_array, 0, + unsorted_array.size() - 1 + ); + std::cout << "Sorted array is : " << std::endl; + sorting::random_pivot_quick_sort::showArray(sorted_array); + return 0; +} From 97afa0e3e4d817d2fa238e3213668bbb988e74e4 Mon Sep 17 00:00:00 2001 From: Nitin Sharma <32377892+foo290@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:53:29 +0530 Subject: [PATCH 08/22] feat: add Sublist Search Algorithm (#1513) * feat: add sublist search algorithm * updating DIRECTORY.md * clang-format and clang-tidy fixes for e59bc3bf * Update search/sublist_search.cpp header docs Co-authored-by: David Leal * Update search/sublist_search.cpp docs Co-authored-by: David Leal * Update docs search/sublist_search.cpp Co-authored-by: David Leal * Update docs search/sublist_search.cpp Co-authored-by: David Leal * Update minor docs in search/sublist_search.cpp Co-authored-by: David Leal * made test function non static Co-authored-by: David Leal * test docs updated Co-authored-by: David Leal * namespaces added for search algo, docs added for test cases * [feat/fix/docs]: Perform some necessary changes * clang-format and clang-tidy fixes for 5a02b336 * test cases docs added, merge fixed * clang-format and clang-tidy fixes for be0160b4 * one liner docs added * clang-format and clang-tidy fixes for 95b362f3 * some final docs fixes * clang-format and clang-tidy fixes for 798972e9 * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * docs updated for one line docs * clang-format and clang-tidy fixes for aebae1df * added one liner docs * clang-format and clang-tidy fixes for f6913b75 * Update search/sublist_search.cpp Co-authored-by: David Leal * Update search/sublist_search.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 66d1b87f * Update search/sublist_search.cpp Co-authored-by: David Leal * Update search/sublist_search.cpp Co-authored-by: David Leal * Apply suggestions from code review * clang-format and clang-tidy fixes for dc5b0c6c * Apply suggestions from code review * clang-format and clang-tidy fixes for 6436932f * Apply suggestions from code review * clang-format and clang-tidy fixes for 35f39b57 * Update docs search/sublist_search.cpp Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + search/sublist_search.cpp | 370 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 search/sublist_search.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 38e65a8a6..964b49aeb 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -268,6 +268,7 @@ * [Linear Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/linear_search.cpp) * [Median Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/median_search.cpp) * [Saddleback Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/saddleback_search.cpp) + * [Sublist Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/sublist_search.cpp) * [Ternary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/ternary_search.cpp) * [Text Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/text_search.cpp) diff --git a/search/sublist_search.cpp b/search/sublist_search.cpp new file mode 100644 index 000000000..9f854ce57 --- /dev/null +++ b/search/sublist_search.cpp @@ -0,0 +1,370 @@ +/** + * @file + * @brief Implementation of the [Sublist Search + * Algorithm](https://www.geeksforgeeks.org/sublist-search-search-a-linked-list-in-another-list) + * @details + * + * ### Algorithm + * + * * Sublist search is used to detect a presence of one list in another list. + * * Suppose we have a single-node list (let's say the first list), and we + * want to ensure that the list is present in another list (let's say the + * second list), then we can perform the sublist search to find it. + * + * * For instance, the first list contains these elements: 23 -> 30 -> 41, + * and the second list contains these elements: 10 -> 15 -> 23 -> 30 -> 41 + * -> 49. At a glance, we see that the first list presents in the second list. + * + * ### Working + * + * * The sublist search algorithm works by comparing the first element + * of the first list with the first element of the second list. + * * If the two values don't match, it goes to the next element of the + * second list. It does this until the two values match. + * + * @author [Nitin Sharma](https://github.com/foo290) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace search + * @brief Searching algorithms + */ +namespace search { +/** + * @namespace sublist_search + * @brief Functions for the [Sublist + * Search](https://www.geeksforgeeks.org/sublist-search-search-a-linked-list-in-another-list) + * implementation + */ +namespace sublist_search { +/** + * @brief A Node structure representing a single link Node in a linked list + */ +struct Node { + uint32_t data = 0; ///< the key/value of the node + Node *next{}; ///< pointer to the next node +}; + +/** + * @brief A simple function to print the linked list + * @param start The head of the linked list + * @returns void + */ +void printLinkedList(Node *start) { + while (start != nullptr) { + std::cout << "->" << start->data; + start = start->next; + } + std::cout << std::endl; +} + +/** + * @brief Give a vector of data, + * it adds each element of vector in the linked list and return the address of + * head pointer. + * @param data A vector of "int" containing the data that is supposed to be + * stored in nodes of linked list. + * @returns Node* A head pointer to the linked list. + */ +Node *makeLinkedList(const std::vector &data) { + /// This is used in test cases for rapidly creating linked list with 100+ + /// elements, instead of hard-coding 100 elements in test cases. + Node *head = nullptr; + Node *tail = nullptr; + for (int i : data) { + Node *node = new Node; + node->data = i; + node->next = nullptr; + if (head == nullptr) { + head = node; + tail = node; + } else { + tail->next = node; + tail = tail->next; + } + } + return head; +} + +/** + * @brief Main searching function + * @param sublist A linked list which is supposed to be searched in mainList. + * @param mainList A linked list in which sublist will be searched. + * @returns true if the sublist is found + * @returns false if the sublist is NOT found + */ +bool sublistSearch(Node *sublist, Node *mainList) { + if (sublist == nullptr || mainList == nullptr) { + return false; + } + + /// Initialize target pointer to the head node of sublist. + Node *target_ptr = sublist; + + while (mainList != nullptr) { + /// Initialize main pointer to the current node of main list. + Node *main_ptr = mainList; + + while (target_ptr != nullptr) { + if (main_ptr == nullptr) { + return false; + + } else if (main_ptr->data == target_ptr->data) { + /// If the data of target node and main node is equal then move + /// to the next node of both lists. + target_ptr = target_ptr->next; + main_ptr = main_ptr->next; + + } else { + break; + } + } + + if (target_ptr == nullptr) { + /// Is target pointer becomes null that means the target list is + /// been traversed without returning false. Which means the sublist + /// has been found and return ture. + return true; + } + + /// set the target pointer again to stating point of target list. + target_ptr = sublist; + + /// set the main pointer to the next element of the main list and repeat + /// the algo. + mainList = mainList->next; + } + + /// If the main list is exhausted, means sublist does not found, return + /// false + return false; +} + +} // namespace sublist_search +} // namespace search + +/** + * @brief class encapsulating the necessary test cases + */ +class TestCases { + private: + /** + * @brief A function to print given message on console. + * @tparam T Type of the given message. + * @returns void + * */ + template + void log(T msg) { + // It's just to avoid writing cout and endl + std::cout << "[TESTS] : ---> " << msg << std::endl; + } + + public: + /** + * @brief Executes test cases + * @returns void + * */ + void runTests() { + log("Running Tests..."); + + testCase_1(); + testCase_2(); + testCase_3(); + + log("Test Cases over!"); + std::cout << std::endl; + } + + /** + * @brief A test case contains edge case, Only contains one element. + * @returns void + * */ + void testCase_1() { + const bool expectedOutput = true; ///< Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + log("This is test case 1 for sublist search Algorithm : "); + log("Description:"); + log(" EDGE CASE : Only contains one element"); + + std::vector sublistData = { + 6}; ///< Data to make linked list which will be the sublist + std::vector mainlistData = { + 2, 5, 6, 7, + 8}; ///< Data to make linked list which will be the main list + + search::sublist_search::Node *sublistLL = + search::sublist_search::makeLinkedList( + sublistData); ///< Sublist to be searched + search::sublist_search::Node *mainlistLL = + search::sublist_search::makeLinkedList( + mainlistData); ///< Main list in which sublist is to be + ///< searched + + bool exists = search::sublist_search::sublistSearch( + sublistLL, mainlistLL); ///< boolean, if sublist exist or not + + log("Checking assert expression..."); + assert(exists == expectedOutput); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 1 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + + delete (sublistLL); + delete (mainlistLL); + } + + /** + * @brief A test case which contains main list of 100 elements and sublist + * of 20. + * @returns void + * */ + void testCase_2() { + const bool expectedOutput = true; /// Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + log("This is test case 2 for sublist search Algorithm : "); + log("Description:"); + log(" contains main list of 100 elements and sublist of 20"); + + std::vector sublistData( + 20); ///< Data to make linked list which will be the sublist + std::vector mainlistData( + 100); ///< Main list in which sublist is to be searched + + for (int i = 0; i < 100; i++) { + /// Inserts 100 elements in main list + mainlistData[i] = i + 1; + } + + int temp = 0; + for (int i = 45; i < 65; i++) { + /// Inserts 20 elements in sublist + sublistData[temp] = i + 1; + temp++; + } + + search::sublist_search::Node *sublistLL = + search::sublist_search::makeLinkedList( + sublistData); ///< Sublist to be searched + search::sublist_search::Node *mainlistLL = + search::sublist_search::makeLinkedList( + mainlistData); ///< Main list in which sublist is to be + ///< searched + + bool exists = search::sublist_search::sublistSearch( + sublistLL, mainlistLL); ///< boolean, if sublist exist or not + + log("Checking assert expression..."); + assert(exists == expectedOutput); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 2 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + } + + /** + * @brief A test case which contains main list of 50 elements and sublist + * of 20. + * @returns void + * */ + void testCase_3() { + const bool expectedOutput = false; ///< Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + log("This is test case 3 for sublist search Algorithm : "); + log("Description:"); + log(" contains main list of 50 elements and sublist of 20"); + + std::vector sublistData(20); ///< Sublist to be searched + std::vector mainlistData( + 50); ///< Main list in which sublist is to be searched + + for (int i = 0; i < 50; i++) { + /// Inserts 100 elements in main list + mainlistData.push_back(i + 1); + } + + for (int i = 45; i < 65; i++) { + /// Inserts 20 elements in sublist + sublistData.push_back(i + 1); + } + + search::sublist_search::Node *sublistLL = + search::sublist_search::makeLinkedList( + sublistData); ///< Sublist to be searched + search::sublist_search::Node *mainlistLL = + search::sublist_search::makeLinkedList( + mainlistData); ///< Main list in which sublist is to be + ///< searched + + bool exists = search::sublist_search::sublistSearch( + sublistLL, mainlistLL); ///< boolean, if sublist exist or not + + log("Checking assert expression..."); + assert(exists == expectedOutput); + log("Assertion check passed!"); + + log("[PASS] : TEST CASE 3 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); + } +}; + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + TestCases tc; + tc.runTests(); +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // run self-test implementations + + std::vector mainlistData = { + 2, 5, 6, 7, 8}; ///< Main list in which sublist is to be searched + std::vector sublistData = {6, 8}; ///< Sublist to be searched + + search::sublist_search::Node *mainlistLL = + search::sublist_search::makeLinkedList(mainlistData); + search::sublist_search::Node *sublistLL = + search::sublist_search::makeLinkedList( + sublistData); ///< Main list in which sublist is to be + ///< searched + + bool exists = search::sublist_search::sublistSearch( + sublistLL, + mainlistLL); ///< boolean to check if the sublist exists or not + + std::cout << "Sublist: " << std::endl; + search::sublist_search::printLinkedList(sublistLL); + + std::cout << "Main list: " << std::endl; + search::sublist_search::printLinkedList(mainlistLL); + std::cout << std::endl; + + if (exists) { + std::cout << "[TRUE] - sublist found in main list\n"; + } else { + std::cout << "[FALSE] - sublist NOT found in main list\n"; + } + return 0; +} From 34556ad93925310cb8f92a6a0142bdbac4482f8a Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:13:57 +0530 Subject: [PATCH 09/22] Create count_of_set_bits.cpp (#1515) * Create count_of_set_bits.cpp * Update count_of_set_bits.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for d0dc7eb3 * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for f8606e8f * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 40e0f745 * Update count_of_set_bits.cpp * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal * Update bit_manipulation/count_of_set_bits.cpp Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + bit_manipulation/count_of_set_bits.cpp | 80 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 bit_manipulation/count_of_set_bits.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 964b49aeb..b65d77995 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -10,6 +10,7 @@ * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) ## Bit Manipulation + * [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/count_of_set_bits.cpp) * [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp) ## Ciphers diff --git a/bit_manipulation/count_of_set_bits.cpp b/bit_manipulation/count_of_set_bits.cpp new file mode 100644 index 000000000..87f01d161 --- /dev/null +++ b/bit_manipulation/count_of_set_bits.cpp @@ -0,0 +1,80 @@ +/** + * @file + * @brief Implementation to [count sets + * bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an + * integer. + * + * @details + * We are given an integer number. Let’s say, number. The task is to first + * calculate the binary digit of a number and then calculate the total set bits + * of a number. + * + * Set bits in a binary number is represented by 1. Whenever we calculate the + * binary number of an integer value it is formed as the combination of 0’s and + * 1’s. So digit 1 is known as a set bit in computer terms. + * Time Complexity: O(log n) + * Space complexity: O(1) + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for io operations +#include /// for std::vector + +/** + * @namespace bit_manipulation + * @brief Bit manipulation algorithms + */ +namespace bit_manipulation { +/** + * @namespace count_of_set_bits + * @brief Functions for the [count sets + * bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) + * implementation + */ +namespace count_of_set_bits { +/** + * @brief The main function implements set bit count + * @param n is the number whose set bit will be counted + * @returns the count of the number set bit in the binary representation of `n` + */ +std::uint64_t countSetBits(int n) { + int count = 0; // "count" variable is used to count number of 1's in binary + // representation of the number + while (n != 0) { + count += n & 1; + n = n >> 1; // n=n/2 + } + return count; +} +} // namespace count_of_set_bits +} // namespace bit_manipulation + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // n = 4 return 1 + assert(bit_manipulation::count_of_set_bits::countSetBits(4) == 1); + // n = 6 return 2 + assert(bit_manipulation::count_of_set_bits::countSetBits(6) == 2); + // n = 13 return 3 + assert(bit_manipulation::count_of_set_bits::countSetBits(13) == 3); + // n = 9 return 2 + assert(bit_manipulation::count_of_set_bits::countSetBits(9) == 2); + // n = 15 return 4 + assert(bit_manipulation::count_of_set_bits::countSetBits(15) == 4); + // n = 25 return 3 + assert(bit_manipulation::count_of_set_bits::countSetBits(25) == 3); + std::cout << "All test cases successfully passed!" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 1ab5e4e56466a3a9b06c330c4e52cc7bb06699c3 Mon Sep 17 00:00:00 2001 From: Jxtopher <39927513+Jxtopher@users.noreply.github.com> Date: Fri, 9 Jul 2021 21:00:34 +0200 Subject: [PATCH 10/22] feat: Replace "\n" -> std::endl (#1530) Co-authored-by: David Leal --- backtracking/graph_coloring.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp index f2ac572c5..0f82a77bf 100644 --- a/backtracking/graph_coloring.cpp +++ b/backtracking/graph_coloring.cpp @@ -30,11 +30,11 @@ namespace backtracking { */ template void printSolution(const std::array & color) { - std::cout << "Following are the assigned colors\n"; + std::cout << "Following are the assigned colors" << std::endl; for (auto &col : color) { std::cout << col; } - std::cout << "\n"; + std::cout << std::endl; } /** A utility function to check if the current color assignment is safe for From 6115bc298154dc996c0315e79673fa436d02f6ea Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Sat, 10 Jul 2021 00:32:28 +0530 Subject: [PATCH 11/22] feat: Add House Robber algorithm (#1524) * Create house_robber.cpp * updating DIRECTORY.md * Update dynamic_programming/house_robber.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update dynamic_programming/house_robber.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update dynamic_programming/house_robber.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * clang-format and clang-tidy fixes for c00823e8 * Update house_robber.cpp * clang-format and clang-tidy fixes for cdf701c2 * Update house_robber.cpp * clang-format and clang-tidy fixes for 39c3719f * Update dynamic_programming/house_robber.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * clang-format and clang-tidy fixes for 126e3f21 * Update house_robber.cpp * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * Update house_robber.cpp * clang-format and clang-tidy fixes for 474a5f0b * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * Update dynamic_programming/house_robber.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 203cce31 * Update house_robber.cpp * Update house_robber.cpp * Update house_robber.cpp * clang-format and clang-tidy fixes for 6b0bea93 * Apply suggestions from code review * Apply suggestions from code review * clang-format and clang-tidy fixes for 913baf88 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + dynamic_programming/house_robber.cpp | 114 +++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 dynamic_programming/house_robber.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index b65d77995..ea7ed6779 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -74,6 +74,7 @@ * [Egg Dropping Puzzle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/egg_dropping_puzzle.cpp) * [Fibonacci Bottom Up](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/fibonacci_bottom_up.cpp) * [Floyd Warshall](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/floyd_warshall.cpp) + * [House Robber](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/house_robber.cpp) * [Kadane](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/kadane.cpp) * [Kadane2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/kadane2.cpp) * [Longest Common String](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/longest_common_string.cpp) diff --git a/dynamic_programming/house_robber.cpp b/dynamic_programming/house_robber.cpp new file mode 100644 index 000000000..0d238b9c1 --- /dev/null +++ b/dynamic_programming/house_robber.cpp @@ -0,0 +1,114 @@ +/** + * @file + * @brief Implementation of [House Robber + * Problem](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber) + * algorithm + * @details + * Solution of House robber problem uses a dynamic programming concept that + * works in \f$O(n)\f$ time and works in \f$O(1)\f$ space. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for std::max +#include /// for io operations +#include /// for std::vector + +/** + * @namespace dynamic_programming + * @brief Dynamic Programming algorithms + */ +namespace dynamic_programming { +/** + * @namespace house_robber + * @brief Functions for the [House + * Robber](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber) + * algorithm + */ +namespace house_robber { +/** + * @brief The main function that implements the House Robber algorithm using + * dynamic programming + * @param money array containing money in the ith house + * @param n size of array + * @returns maximum amount of money that can be robbed + */ +std::uint32_t houseRobber(const std::vector &money, + const uint32_t &n) { + if (n == 0) { // if there is no house + return 0; + } + if (n == 1) { // if there is only one house + return money[0]; + } + if (n == 2) { // if there are two houses, one with the maximum amount of + // money will be robbed + return std::max(money[0], money[1]); + } + uint32_t max_value = 0; // contains maximum stolen value at the end + uint32_t value1 = money[0]; + uint32_t value2 = std::max(money[0], money[1]); + for (uint32_t i = 2; i < n; i++) { + max_value = std::max(money[i] + value1, value2); + value1 = value2; + value2 = max_value; + } + + return max_value; +} +} // namespace house_robber +} // namespace dynamic_programming + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // Test 1 + // [1, 2, 3, 1] return 4 + std::vector array1 = {1, 2, 3, 1}; + std::cout << "Test 1... "; + assert( + dynamic_programming::house_robber::houseRobber(array1, array1.size()) == + 4); // here the two non-adjacent houses that are robbed are first and + // third with total sum money as 4 + std::cout << "passed" << std::endl; + + // Test 2 + // [6, 7, 1, 3, 8, 2, 4] return 19 + std::vector array2 = {6, 7, 1, 3, 8, 2, 4}; + std::cout << "Test 2... "; + assert( + dynamic_programming::house_robber::houseRobber(array2, array2.size()) == + 19); // here the four non-adjacent houses that are robbed are first, + // third, fifth and seventh with total sum money as 19 + std::cout << "passed" << std::endl; + + // Test 3 + // [] return 0 + std::vector array3 = {}; + std::cout << "Test 3... "; + assert( + dynamic_programming::house_robber::houseRobber(array3, array3.size()) == + 0); // since there is no house no money can be robbed + std::cout << "passed" << std::endl; + + // Test 4 + // [2,7,9,3,1] return 12 + std::vector array4 = {2, 7, 9, 3, 1}; + std::cout << "Test 4... "; + assert( + dynamic_programming::house_robber::houseRobber(array4, array4.size()) == + 12); // here the three non-adjacent houses that are robbed are first, + // third and fifth with total sum money as 12 + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 394811e601743d39650dda263a07fa61bf030b67 Mon Sep 17 00:00:00 2001 From: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> Date: Sat, 10 Jul 2021 00:33:57 +0530 Subject: [PATCH 12/22] fix: spelling error in `CONTRIBUTING.md` (#1531) Co-authored-by: David Leal --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72014433d..2ff8cb72c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -113,7 +113,7 @@ bool func(int param1, T param2) { * @returns void */ static void test() { - /* desciptions of the following test */ + /* descriptions of the following test */ assert(func(...) == ...); // this ensures that the algorithm works as expected // can have multiple checks From 82290e72c540e63aabd7af9abe487bc0a4aa6d64 Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:20:56 +0530 Subject: [PATCH 13/22] tests: Add test in `cycle_sort.cpp` (#1520) * Update cycle_sort.cpp * Update sorting/cycle_sort.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update sorting/cycle_sort.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * clang-format and clang-tidy fixes for 2601c621 * Update cycle_sort.cpp * Update cycle_sort.cpp * Update cycle_sort.cpp * clang-format and clang-tidy fixes for 39cf3f34 * Update sorting/cycle_sort.cpp Co-authored-by: David Leal * Update cycle_sort.cpp * Update cycle_sort.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- sorting/cycle_sort.cpp | 46 ++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/sorting/cycle_sort.cpp b/sorting/cycle_sort.cpp index 7700b2115..8acf462af 100644 --- a/sorting/cycle_sort.cpp +++ b/sorting/cycle_sort.cpp @@ -2,14 +2,12 @@ * @file * @brief Implementation of [Cycle * sort](https://en.wikipedia.org/wiki/Cycle_sort) algorithm - * * @details - * Cycle Sort is a sorting algorithm that works in \f$O(n^2)\f$ time in best cas - * and works in \f$O(n^2)\f$ in worst case. If a element is already at its + * Cycle Sort is a sorting algorithm that works in \f$O(n^2)\f$ time in the best + * case and works in \f$O(n^2)\f$ in worst case. If a element is already at its * correct position, do nothing. If a element is not at its correct position, * we then need to move it to its correct position by computing the correct * positions.Therefore, we should make sure the duplicate elements. - * * @author [TsungHan Ho](https://github.com/dalaoqi) */ @@ -38,14 +36,14 @@ namespace cycle_sort { template std::vector cycleSort(const std::vector &in_arr) { std::vector arr(in_arr); - for (size_t cycle_start = 0; cycle_start <= arr.size() - 1; cycle_start++) { + for (int cycle_start = 0; cycle_start <= arr.size() - 1; cycle_start++) { // initialize item T item = arr[cycle_start]; // Count the number of elements smaller than item, this number is the // correct index of item. int pos = cycle_start; - for (size_t i = cycle_start + 1; i < arr.size(); i++) { + for (int i = cycle_start + 1; i < arr.size(); i++) { if (arr[i] < item) { pos++; } @@ -58,8 +56,11 @@ std::vector cycleSort(const std::vector &in_arr) { // duplicate elements while (item == arr[pos]) pos += 1; - std::swap(item, arr[pos]); - + if (pos == cycle_start) { + continue; + } else { + std::swap(item, arr[pos]); + } // Rest of the elements while (pos != cycle_start) { pos = cycle_start; @@ -71,7 +72,11 @@ std::vector cycleSort(const std::vector &in_arr) { } // duplicate elements while (item == arr[pos]) pos += 1; - std::swap(item, arr[pos]); + if (item == arr[pos]) { + continue; + } else { + std::swap(item, arr[pos]); + } } } return arr; @@ -84,11 +89,11 @@ std::vector cycleSort(const std::vector &in_arr) { * @returns void */ static void test() { - // [506, 48, 123, 79, 0, 362, 951, 500, 0] return [0, 0, 48, 79, 123, 362, - // 500, 506, 951] - std::vector array1 = {506, 48, 123, 79, 0, 362, 951, 500, 0}; + // Test 1 + // [4, 3, 2, 1] return [1, 2, 3, 4] + std::vector array1 = {4, 3, 2, 1}; std::cout << "Test 1... "; - std::vector arr1 = sorting::cycle_sort::cycleSort(array1); + std::vector arr1 = sorting::cycle_sort::cycleSort(array1); assert(std::is_sorted(std::begin(arr1), std::end(arr1))); std::cout << "passed" << std::endl; @@ -98,6 +103,21 @@ static void test() { std::vector arr2 = sorting::cycle_sort::cycleSort(array2); assert(std::is_sorted(std::begin(arr2), std::end(arr2))); std::cout << "passed" << std::endl; + + // Test 3 + // [3, 3, 3, 3] return [3, 3, 3, 3] + std::vector array3 = {3, 3, 3, 3}; + std::cout << "Test 3... "; + std::vector arr3 = sorting::cycle_sort::cycleSort(array3); + assert(std::is_sorted(std::begin(arr3), std::end(arr3))); + std::cout << "passed" << std::endl; + + // [9, 4, 6, 8, 14, 3] return [9, 4, 6, 8, 14, 3] + std::vector array4 = {3, 4, 6, 8, 9, 14}; + std::cout << "Test 4... "; + std::vector arr4 = sorting::cycle_sort::cycleSort(array4); + assert(std::is_sorted(std::begin(arr4), std::end(arr4))); + std::cout << "passed" << std::endl; } /** From e059765f79d5a6dffe6b7554f53e030dfc2e7e2d Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:49:03 +0530 Subject: [PATCH 14/22] Create subset_sum.cpp (#1517) * Create subset_sum.cpp * Update subset_sum.cpp * Update subset_sum.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for 4827805a * Update subset_sum.cpp * clang-format and clang-tidy fixes for dac32465 * Update backtracking/subset_sum.cpp Co-authored-by: Filip Hlasek * Update backtracking/subset_sum.cpp Co-authored-by: Filip Hlasek * clang-format and clang-tidy fixes for 1328571c * Update backtracking/subset_sum.cpp Co-authored-by: Filip Hlasek * Update subset_sum.cpp * clang-format and clang-tidy fixes for 2325e165 * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * clang-format and clang-tidy fixes for 1b82d499 * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 31a1deae * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update backtracking/subset_sum.cpp Co-authored-by: David Leal * Update subset_sum.cpp * clang-format and clang-tidy fixes for 9cd07635 * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update backtracking/subset_sum.cpp Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> * Update subset_sum.cpp * Update subset_sum.cpp * clang-format and clang-tidy fixes for 2405a142 * Update subset_sum.cpp * clang-format and clang-tidy fixes for 383baeb3 * Update subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp * Update backtracking/subset_sum.cpp Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Filip Hlasek Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + backtracking/subset_sum.cpp | 106 ++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 backtracking/subset_sum.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index ea7ed6779..f56b46e2e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -7,6 +7,7 @@ * [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens_all_solution_optimised.cpp) * [Nqueen Print All Solutions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/nqueen_print_all_solutions.cpp) * [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/rat_maze.cpp) + * [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) ## Bit Manipulation diff --git a/backtracking/subset_sum.cpp b/backtracking/subset_sum.cpp new file mode 100644 index 000000000..fad820920 --- /dev/null +++ b/backtracking/subset_sum.cpp @@ -0,0 +1,106 @@ +/** + * @file + * @brief Implementation of the [Subset + * Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem. + * @details + * We are given an array and a sum value. The algorithm finds all + * the subsets of that array with sum equal to the given sum and return such + * subsets count. This approach will have exponential time complexity. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace Subsets + * @brief Functions for the [Subset + * Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem. + */ +namespace subset_sum { +/** + * @brief The main function implements count of subsets + * @param sum is the required sum of any subset + * @param in_arr is the input array + * @returns count of the number of subsets with required sum + */ +uint64_t number_of_subsets(int32_t sum, const std::vector &in_arr) { + int32_t nelement = in_arr.size(); + uint64_t count_of_subset = 0; + + for (int32_t i = 0; i < (1 << (nelement)); i++) { + int32_t check = 0; + for (int32_t j = 0; j < nelement; j++) { + if (i & (1 << j)) { + check += (in_arr[j]); + } + } + if (check == sum) { + count_of_subset++; + } + } + return count_of_subset; +} +} // namespace subset_sum +} // namespace backtracking + +/** + * @brief Test implementations + * @returns void + */ +static void test() { + // 1st test + std::cout << "1st test "; + std::vector array1 = {-7, -3, -2, 5, 8}; // input array + assert(backtracking::subset_sum::number_of_subsets(0, array1) == + 2); // first argument in subset_sum function is the required sum and + // second is the input array + std::cout << "passed" << std::endl; + + // 2nd test + std::cout << "2nd test "; + std::vector array2 = {1, 2, 3, 3}; + assert(backtracking::subset_sum::number_of_subsets(6, array2) == + 3); // here we are expecting 3 subsets which sum up to 6 i.e. + // {(1,2,3),(1,2,3),(3,3)} + std::cout << "passed" << std::endl; + + // 3rd test + std::cout << "3rd test "; + std::vector array3 = {1, 1, 1, 1}; + assert(backtracking::subset_sum::number_of_subsets(1, array3) == + 4); // here we are expecting 4 subsets which sum up to 1 i.e. + // {(1),(1),(1),(1)} + std::cout << "passed" << std::endl; + + // 4th test + std::cout << "4th test "; + std::vector array4 = {3, 3, 3, 3}; + assert(backtracking::subset_sum::number_of_subsets(6, array4) == + 6); // here we are expecting 6 subsets which sum up to 6 i.e. + // {(3,3),(3,3),(3,3),(3,3),(3,3),(3,3)} + std::cout << "passed" << std::endl; + + // Test 5 + std::cout << "5th test "; + std::vector array5 = {}; + assert(backtracking::subset_sum::number_of_subsets(6, array5) == + 0); // here we are expecting 0 subsets which sum up to 6 i.e. we + // cannot select anything from an empty array + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 7bab516e59c10a2c51e5a24a55b9c7e20442115d Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Sat, 17 Jul 2021 00:11:54 +0530 Subject: [PATCH 15/22] feat: Add the Wave Sort algorithm (#1525) * Create wave_sort.cpp * Update wave_sort.cpp * Update wave_sort.cpp * Update wave_sort.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for 196165e7 * Update wave_sort.cpp * Update sorting/wave_sort.cpp Co-authored-by: David Leal * Update sorting/wave_sort.cpp Co-authored-by: David Leal * Update sorting/wave_sort.cpp Co-authored-by: David Leal * Update wave_sort.cpp * clang-format and clang-tidy fixes for b5f9663f * Update sorting/wave_sort.cpp Co-authored-by: David Leal * Update sorting/wave_sort.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 8651884e Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + sorting/wave_sort.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 sorting/wave_sort.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index f56b46e2e..00757255a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -311,6 +311,7 @@ * [Strand Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/strand_sort.cpp) * [Swap Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/swap_sort.cpp) * [Tim Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/tim_sort.cpp) + * [Wave Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/wave_sort.cpp) * [Wiggle Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/wiggle_sort.cpp) ## Strings diff --git a/sorting/wave_sort.cpp b/sorting/wave_sort.cpp new file mode 100644 index 000000000..85fdb61ad --- /dev/null +++ b/sorting/wave_sort.cpp @@ -0,0 +1,94 @@ +/** + * @file + * @brief Implementation of the [Wave + * sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) algorithm + * @details + * Wave Sort is a sorting algorithm that works in \f$O(nlogn)\f$ time assuming + * the sort function used works in \f$O(nlogn)\f$ time. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for std::is_sorted, std::swap +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace sorting + * @brief Sorting algorithms + */ +namespace sorting { +/** + * @namespace wave_sort + * @brief Functions for the [Wave + * sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) implementation + */ +namespace wave_sort { +/** + * @brief The main function implements that implements the Wave Sort algorithm + * @tparam T type of array + * @param in_arr array to be sorted + * @returns arr the wave sorted array + */ +template +std::vector waveSort(const std::vector &in_arr, int64_t n) { + std::vector arr(in_arr); + + for (int64_t i = 0; i < n; i++) { + arr[i] = in_arr[i]; + } + std::sort(arr.begin(), arr.end()); + for (int64_t i = 0; i < n - 1; i += 2) { // swap all the adjacent elements + std::swap(arr[i], arr[i + 1]); + } + return arr; +} +} // namespace wave_sort +} // namespace sorting + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // [10, 90, 49, 2, 1, 5, 23] return [2, 1, 10, 5, 49, 23, 90] + std::vector array1 = {10, 90, 49, 2, 1, 5, 23}; + std::cout << "Test 1... "; + std::vector arr1 = sorting::wave_sort::waveSort(array1, 7); + const std::vector o1 = {2, 1, 10, 5, 49, 23, 90}; + assert(arr1 == o1); + std::cout << "passed" << std::endl; + + // [1, 3, 4, 2, 7, 8] return [2, 1, 4, 3, 8, 7] + std::vector array2 = {1, 3, 4, 2, 7, 8}; + std::cout << "Test 2... "; + std::vector arr2 = sorting::wave_sort::waveSort(array2, 6); + const std::vector o2 = {2, 1, 4, 3, 8, 7}; + assert(arr2 == o2); + std::cout << "passed" << std::endl; + + // [3, 3, 3, 3] return [3, 3, 3, 3] + std::vector array3 = {3, 3, 3, 3}; + std::cout << "Test 3... "; + std::vector arr3 = sorting::wave_sort::waveSort(array3, 4); + const std::vector o3 = {3, 3, 3, 3}; + assert(arr3 == o3); + std::cout << "passed" << std::endl; + + // [9, 4, 6, 8, 14, 3] return [4, 3, 8, 6, 14, 9] + std::vector array4 = {9, 4, 6, 8, 14, 3}; + std::cout << "Test 4... "; + std::vector arr4 = sorting::wave_sort::waveSort(array4, 6); + const std::vector o4 = {4, 3, 8, 6, 14, 9}; + assert(arr4 == o4); + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From ae8685fb6a20d2e1d8d70b69182d218c1ad3f774 Mon Sep 17 00:00:00 2001 From: Jxtopher <39927513+Jxtopher@users.noreply.github.com> Date: Sat, 17 Jul 2021 12:06:19 +0200 Subject: [PATCH 16/22] feat: solving magic sequence problem with backtracking (#1533) * Create magic_sequence.cpp * update code formatter * updating DIRECTORY.md * Update magic_sequence.cpp * Delete settings.json * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update magic_sequence.cpp * Revert "Delete settings.json" This reverts commit 64b08dee6d0d9fbe39dbdff255adc6f4b8937560. * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 2263f033 * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update magic_sequence.cpp * Update magic_sequence.cpp * Update magic_sequence.cpp * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update magic_sequence.cpp * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for f889fb4f * Update backtracking/magic_sequence.cpp Co-authored-by: David Leal * Update magic_sequence.cpp * fix: Apply suggestions from code review Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + backtracking/magic_sequence.cpp | 135 ++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 backtracking/magic_sequence.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 00757255a..2c919e0da 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -2,6 +2,7 @@ ## Backtracking * [Graph Coloring](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/graph_coloring.cpp) * [Knight Tour](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/knight_tour.cpp) + * [Magic Sequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/magic_sequence.cpp) * [Minimax](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/minimax.cpp) * [N Queens](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens.cpp) * [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens_all_solution_optimised.cpp) diff --git a/backtracking/magic_sequence.cpp b/backtracking/magic_sequence.cpp new file mode 100644 index 000000000..13a260dc9 --- /dev/null +++ b/backtracking/magic_sequence.cpp @@ -0,0 +1,135 @@ +/* + * @brief [Magic sequence](https://www.csplib.org/Problems/prob019/) + * implementation + * + * @details Solve the magic sequence problem with backtracking + * + * "A magic sequence of length $n$ is a sequence of integers $x_0 + * \ldots x_{n-1}$ between $0$ and $n-1$, such that for all $i$ + * in $0$ to $n-1$, the number $i$ occurs exactly $x_i$ times in + * the sequence. For instance, $6,2,1,0,0,0,1,0,0,0$ is a magic + * sequence since $0$ occurs $6$ times in it, $1$ occurs twice, etc." + * Quote taken from the [CSPLib](https://www.csplib.org/Problems/prob019/) + * website + * + * @author [Jxtopher](https://github.com/Jxtopher) + */ + +#include /// for std::count +#include /// for assert +#include /// for IO operations +#include /// for std::list +#include /// for std::accumulate +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace magic_sequence + * @brief Functions for the [Magic + * sequence](https://www.csplib.org/Problems/prob019/) implementation + */ +namespace magic_sequence { +using sequence_t = + std::vector; ///< Definition of the sequence type +/** + * @brief Print the magic sequence + * @param s working memory for the sequence + */ +void print(const sequence_t& s) { + for (const auto& item : s) std::cout << item << " "; + std::cout << std::endl; +} + +/** + * @brief Check if the sequence is magic + * @param s working memory for the sequence + * @returns true if it's a magic sequence + * @returns false if it's NOT a magic sequence + */ +bool is_magic(const sequence_t& s) { + for (unsigned int i = 0; i < s.size(); i++) { + if (std::count(s.cbegin(), s.cend(), i) != s[i]) { + return false; + } + } + return true; +} + +/** + * @brief Sub-solutions filtering + * @param s working memory for the sequence + * @param depth current depth in tree + * @returns true if the sub-solution is valid + * @returns false if the sub-solution is NOT valid + */ +bool filtering(const sequence_t& s, unsigned int depth) { + return std::accumulate(s.cbegin(), s.cbegin() + depth, + static_cast(0)) <= s.size(); +} + +/** + * @brief Solve the Magic Sequence problem + * @param s working memory for the sequence + * @param ret list of the valid magic sequences + * @param depth current depth in the tree + */ +void solve(sequence_t* s, std::list* ret, unsigned int depth = 0) { + if (depth == s->size()) { + if (is_magic(*s)) { + ret->push_back(*s); + } + } else { + for (unsigned int i = 0; i < s->size(); i++) { + (*s)[depth] = i; + if (filtering(*s, depth + 1)) { + solve(s, ret, depth + 1); + } + } + } +} + +} // namespace magic_sequence +} // namespace backtracking + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // test a valid magic sequence + backtracking::magic_sequence::sequence_t s_magic = {6, 2, 1, 0, 0, + 0, 1, 0, 0, 0}; + assert(backtracking::magic_sequence::is_magic(s_magic)); + + // test a non-valid magic sequence + backtracking::magic_sequence::sequence_t s_not_magic = {5, 2, 1, 0, 0, + 0, 1, 0, 0, 0}; + assert(!backtracking::magic_sequence::is_magic(s_not_magic)); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + + // solve magic sequences of size 2 to 11 and print the solutions + for (unsigned int i = 2; i < 12; i++) { + std::cout << "Solution for n = " << i << std::endl; + // valid magic sequence list + std::list list_of_solutions; + // initialization of a sequence + backtracking::magic_sequence::sequence_t s1(i, i); + // launch of solving the problem + backtracking::magic_sequence::solve(&s1, &list_of_solutions); + // print solutions + for (const auto& item : list_of_solutions) { + backtracking::magic_sequence::print(item); + } + } +} From 652c2d2650210d867447618f70dcbfd78ce33a0b Mon Sep 17 00:00:00 2001 From: Nitin Sharma <32377892+foo290@users.noreply.github.com> Date: Sun, 18 Jul 2021 10:32:08 +0530 Subject: [PATCH 17/22] feat: add inorder successor for bst in operations on ds (#1532) * feat: add inorder successor in bst * clang-tidy errors fixed, reference docs link added * updating DIRECTORY.md * clang-format and clang-tidy fixes for f8658fe5 * docs formatting changed, namespace added * clang-format and clang-tidy fixes for f54f31cd * added bullet points in docs * Update operations_on_datastructures/inorder_successor_of_bst.cpp Co-authored-by: David Leal * Update operations_on_datastructures/inorder_successor_of_bst.cpp Co-authored-by: David Leal * Update operations_on_datastructures/inorder_successor_of_bst.cpp Co-authored-by: David Leal * Update operations_on_datastructures/inorder_successor_of_bst.cpp Co-authored-by: David Leal * docs improved * clang-format and clang-tidy fixes for f1b83198 * Update operations_on_datastructures/inorder_successor_of_bst.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 420a4ec1 * Apply suggestions from code review * fix: Apply suggestions from code review * memory leaks patched * clang-format and clang-tidy fixes for ac801a1e Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + .../inorder_successor_of_bst.cpp | 429 ++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 operations_on_datastructures/inorder_successor_of_bst.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 2c919e0da..7f2468bed 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -220,6 +220,7 @@ * [Circular Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_linked_list.cpp) * [Circular Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_queue_using_array.cpp) * [Get Size Of Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/get_size_of_linked_list.cpp) + * [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp) * [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp) * [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp) * [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp) diff --git a/operations_on_datastructures/inorder_successor_of_bst.cpp b/operations_on_datastructures/inorder_successor_of_bst.cpp new file mode 100644 index 000000000..a91c0d715 --- /dev/null +++ b/operations_on_datastructures/inorder_successor_of_bst.cpp @@ -0,0 +1,429 @@ +/** + * @file + * @brief An implementation for finding the [Inorder successor of a binary + * search tree](https://www.youtube.com/watch?v=5cPbNCrdotA) Inorder + * successor of a node is the next node in Inorder traversal of the Binary Tree. + * Inorder Successor is NULL for the last node in Inorder traversal. + * @details + * ### Case 1: The given node has the right node/subtree + * + * * In this case, the left-most deepest node in the right subtree will + * come just after the given node as we go to left deep in inorder. + * - Go deep to left most node in right subtree. + * OR, we can also say in case if BST, find the minimum of the subtree + * for a given node. + * + * ### Case 2: The given node does not have a right node/subtree + * + * #### Method 1: Use parent pointer (store the address of parent nodes) + * * If a node does not have the right subtree, and we already visited the + * node itself, then the next node will be its parent node according to inorder + * traversal, and if we are going to parent from left, then the parent would be + * unvisited. + * * In other words, go to the nearest ancestor for which given node would + * be in left subtree. + * + * #### Method 2: Search from the root node + * * In case if there is no link from a child node to the parent node, we + * need to walk down the tree starting from the root node to the given node, by + * doing so, we are visiting every ancestor of the given node. + * * In order successor would be the deepest node in this path for which + * given node is in left subtree. + * + * @author [Nitin Sharma](https://github.com/foo290) + * */ + +#include /// for assert +#include /// for IO Operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on data structures + */ +namespace operations_on_datastructures { + +/** + * @namespace inorder_successor_of_bst + * @brief Functions for the [Inorder successor of a binary search + * tree](https://www.youtube.com/watch?v=5cPbNCrdotA) implementation + */ +namespace inorder_traversal_of_bst { + +/** + * @brief A Node structure representing a single node in BST + */ +class Node { + public: + int64_t data; ///< The key/value of the node + Node *left; ///< Pointer to Left child + Node *right; ///< Pointer to right child +}; + +/** + * @brief Allocates a new node in heap for given data and returns it's pointer. + * @param data Data for the node. + * @returns A pointer to the newly allocated Node. + * */ +Node *makeNode(int64_t data) { + Node *node = new Node(); + node->data = data; ///< setting data for node + node->left = nullptr; ///< setting left child as null + node->right = nullptr; ///< setting right child as null + return node; +} + +/** + * @brief Inserts the given data in BST while maintaining the properties of BST. + * @param root Pointer to the root node of the BST + * @param data Data to be inserted. + * @returns Node* Pointer to the root node. + * */ +Node *Insert(Node *root, int64_t data) { + if (root == nullptr) { + root = makeNode(data); + } else if (data <= root->data) { + root->left = Insert(root->left, data); + } else { + root->right = Insert(root->right, data); + } + return root; +} + +/** + * @brief Searches the given data in BST and returns the pointer to the node + * containing that data. + * @param root Pointer to the root node of the BST + * @param data Data to be Searched. + * @returns Node* pointer to the found node + * */ +Node *getNode(Node *root, int64_t data) { + if (root == nullptr) { + return nullptr; + } else if (root->data == data) { + return root; /// Node found! + } else if (data > root->data) { + /// Traverse right subtree recursively as the given data is greater than + /// the data in root node, data must be present in right subtree. + return getNode(root->right, data); + } else { + /// Traverse left subtree recursively as the given data is less than the + /// data in root node, data must be present in left subtree. + return getNode(root->left, data); + } +} + +/** + * @brief Finds and return the minimum node in BST. + * @param root A pointer to root node. + * @returns Node* Pointer to the found node + * */ +Node *findMinNode(Node *root) { + if (root == nullptr) { + return root; + } + while (root->left != nullptr) { + root = root->left; + } + return root; +} + +/** + * @brief Prints the BST in inorder traversal using recursion. + * @param root A pointer to the root node of the BST. + * @returns void + * */ +void printInorder(Node *root) { + if (root == nullptr) { + return; + } + + printInorder(root->left); /// recursive call to left subtree + std::cout << root->data << " "; + printInorder(root->right); /// recursive call to right subtree +} + +/** + * @brief This function is used in test cases to quickly create BST containing + * large data instead of hard coding it in code. For a given root, this will add + * all the nodes containing data passes in data vector. + * @param root Pointer to the root node. + * @param data A vector containing integer values which are suppose to be + * inserted as nodes in BST. + * @returns Node pointer to the root node. + * */ +Node *makeBST(Node *root, const std::vector &data) { + for (int64_t values : data) { + root = Insert(root, values); + } + return root; +} + +/** + * @brief Inorder successor of a node is the next node in inorder traversal of + * the Binary Tree. This function takes the root node and the data of the node + * for which we have to find the inorder successor, and returns the inorder + * successor node. + * @details Search from the root node as we need to walk the tree starting from + * the root node to the given node, by doing so, we are visiting every ancestor + * of the given node. In order successor would be the deepest node in this path + * for which given node is in left subtree. Time complexity O(h) + * @param root A pointer to the root node of the BST + * @param data The data (or the data of node) for which we have to find inorder + * successor. + * @returns Node pointer to the inorder successor node. + * */ +Node *getInorderSuccessor(Node *root, int64_t data) { + Node *current = getNode(root, data); + if (current == nullptr) { + return nullptr; + } + + // Case - 1 + if (current->right != nullptr) { + return findMinNode(current->right); + } + // case - 2 + else { + Node *successor = nullptr; + Node *ancestor = root; + + while (ancestor != current && ancestor != nullptr) { + // This means my current node is in left of the root node + if (current->data < ancestor->data) { + successor = ancestor; + ancestor = ancestor->left; // keep going left + } else { + ancestor = ancestor->right; + } + } + return successor; // Nodes with maximum vales will not have a successor + } +} + +/** + * @brief This function clears the memory allocated to entire tree recursively. + * Its just for clean up the memory and not relevant to the actual topic. + * @param root Root node of the tree. + * @returns void + * */ +void deallocate(Node *rootNode) { + if (rootNode == nullptr) { + return; + } + deallocate(rootNode->left); + deallocate(rootNode->right); + delete (rootNode); +} + +} // namespace inorder_traversal_of_bst +} // namespace operations_on_datastructures + +/** + * @brief class encapsulating the necessary test cases + */ +class TestCases { + private: + /** + * @brief A function to print given message on console. + * @tparam T Type of the given message. + * @returns void + * */ + template + void log(T msg) { + // It's just to avoid writing cout and endl + std::cout << "[TESTS] : ---> " << msg << std::endl; + } + + public: + /** + * @brief Executes test cases + * @returns void + * */ + void runTests() { + log("Running Tests..."); + + testCase_1(); + testCase_2(); + testCase_3(); + + log("Test Cases over!"); + std::cout << std::endl; + } + + /** + * @brief A test case contains edge case, printing inorder successor of last + * node. + * @returns void + * */ + void testCase_1() { + const operations_on_datastructures::inorder_traversal_of_bst::Node + *expectedOutput = nullptr; ///< Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("This is test case 1 : "); + log("Description:"); + log(" EDGE CASE : Printing inorder successor for last node in the " + "BST, Output will be nullptr."); + + operations_on_datastructures::inorder_traversal_of_bst::Node *root = + nullptr; + std::vector node_data{ + 20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST + + root = operations_on_datastructures::inorder_traversal_of_bst::makeBST( + root, + node_data); ///< Adding nodes to BST + + std::cout << "Inorder sequence is : "; + operations_on_datastructures::inorder_traversal_of_bst::printInorder( + root); ///< Printing inorder to cross-verify. + std::cout << std::endl; + + operations_on_datastructures::inorder_traversal_of_bst::Node + *inorderSuccessor = operations_on_datastructures:: + inorder_traversal_of_bst::getInorderSuccessor( + root, 78); ///< The inorder successor node for given data + + log("Checking assert expression..."); + assert(inorderSuccessor == expectedOutput); + log("Assertion check passed!"); + + operations_on_datastructures::inorder_traversal_of_bst::deallocate( + root); /// memory cleanup! + + log("[PASS] : TEST CASE 1 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } + + /** + * @brief A test case which contains main list of 100 elements and sublist + * of 20. + * @returns void + * */ + void testCase_2() { + const int expectedOutput = 21; ///< Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("This is test case 2 : "); + + operations_on_datastructures::inorder_traversal_of_bst::Node *root = + nullptr; + std::vector node_data{ + 20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST + + root = operations_on_datastructures::inorder_traversal_of_bst::makeBST( + root, + node_data); ///< Adding nodes to BST + + std::cout << "Inorder sequence is : "; + operations_on_datastructures::inorder_traversal_of_bst::printInorder( + root); ///< Printing inorder to cross-verify. + std::cout << std::endl; + + operations_on_datastructures::inorder_traversal_of_bst::Node + *inorderSuccessor = operations_on_datastructures:: + inorder_traversal_of_bst::getInorderSuccessor( + root, 20); ///< The inorder successor node for given data + + log("Checking assert expression..."); + assert(inorderSuccessor->data == expectedOutput); + log("Assertion check passed!"); + + operations_on_datastructures::inorder_traversal_of_bst::deallocate( + root); /// memory cleanup! + + log("[PASS] : TEST CASE 2 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } + + /** + * @brief A test case which contains main list of 50 elements and sublist + * of 20. + * @returns void + * */ + void testCase_3() { + const int expectedOutput = 110; ///< Expected output of this test + + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("This is test case 3 : "); + + operations_on_datastructures::inorder_traversal_of_bst::Node *root = + nullptr; + std::vector node_data{ + 89, 67, 32, 56, 90, 123, 120, + 110, 115, 6, 78, 7, 10}; ///< Data to make nodes in BST + + root = operations_on_datastructures::inorder_traversal_of_bst::makeBST( + root, + node_data); ///< Adding nodes to BST + + std::cout << "Inorder sequence is : "; + operations_on_datastructures::inorder_traversal_of_bst::printInorder( + root); ///< Printing inorder to cross-verify. + std::cout << std::endl; + + operations_on_datastructures::inorder_traversal_of_bst::Node + *inorderSuccessor = operations_on_datastructures:: + inorder_traversal_of_bst::getInorderSuccessor( + root, 90); ///< The inorder successor node for given data + + log("Checking assert expression..."); + assert(inorderSuccessor->data == expectedOutput); + log("Assertion check passed!"); + + operations_on_datastructures::inorder_traversal_of_bst::deallocate( + root); /// memory cleanup! + + log("[PASS] : TEST CASE 3 PASS!"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } +}; + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + TestCases tc; + tc.runTests(); +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // run self-test implementations + + operations_on_datastructures::inorder_traversal_of_bst::Node *root = + nullptr; ///< root node of the bst + std::vector node_data{3, 4, 5, + 89, 1, 2}; ///< Data to add nodes in BST + + int64_t targetElement = 4; ///< An element to find inorder successor for. + root = operations_on_datastructures::inorder_traversal_of_bst::makeBST( + root, node_data); ///< Making BST + + operations_on_datastructures::inorder_traversal_of_bst::Node + *inorderSuccessor = operations_on_datastructures:: + inorder_traversal_of_bst::getInorderSuccessor(root, targetElement); + + std::cout << "In-order sequence is : "; + operations_on_datastructures::inorder_traversal_of_bst::printInorder(root); + std::cout << std::endl; + + if (inorderSuccessor == nullptr) { + std::cout << "Inorder successor for last node is NULL" << std::endl; + } else { + std::cout << "Target element is : " << targetElement << std::endl; + std::cout << "Inorder successor for target element is : " + << inorderSuccessor->data << std::endl; + } + + deallocate(root); /// memory cleanup! + + return 0; +} From 0e0ba5fc8964495db28d079260176de51cd4d908 Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Thu, 22 Jul 2021 00:40:17 +0530 Subject: [PATCH 18/22] feat: Add the floyd_cycle_detection_algo.cpp file/algorithm (#1540) * search for duplicate number using Floyd algorithm * Update floyd_cycle_detection_algo.cpp Co-authored-by: David Leal --- search/floyd_cycle_detection_algo.cpp | 96 +++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 search/floyd_cycle_detection_algo.cpp diff --git a/search/floyd_cycle_detection_algo.cpp b/search/floyd_cycle_detection_algo.cpp new file mode 100644 index 000000000..ac3d62769 --- /dev/null +++ b/search/floyd_cycle_detection_algo.cpp @@ -0,0 +1,96 @@ +/** + * @file + * @brief Implementation of [Floyd's Cycle + * Detection](https://en.wikipedia.org/wiki/Cycle_detection) algorithm + * @details + * Given an array of integers containing 'n + 1' integers, where each + * integer is in the range [1, n] inclusive. If there is only one duplicate + * number in the input array, this algorithm returns the duplicate number in + * O(1) space and the time complexity is less than O(n^2) without modifying the + * original array, otherwise, it returns -1. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace search + * @brief Search algorithms + */ +namespace search { +/** + * @namespace cycle_detection + * @brief Functions for the [Floyd's Cycle + * Detection](https://en.wikipedia.org/wiki/Cycle_detection) algorithm + */ +namespace cycle_detection { +/** + * @brief The main function implements search algorithm + * @tparam T type of array + * @param in_arr the input array + * @param n size of array + * @returns the duplicate number + */ +template +int32_t duplicateNumber(const std::vector &in_arr, const uint32_t &n) { + if (n == 0 || n == 1) { // to find duplicate in an array its size should be atleast 2 + return -1; + } + uint32_t tortoise = in_arr[0]; // variable tortoise is used for the longer + // jumps in the array + uint32_t hare = in_arr[0]; // variable hare is used for shorter jumps in the array + do { + tortoise = in_arr[tortoise]; + hare = in_arr[in_arr[hare]]; + } while (tortoise != hare); + tortoise = in_arr[0]; + while (tortoise != hare) { + tortoise = in_arr[tortoise]; + hare = in_arr[hare]; + } + return tortoise; +} +} // namespace cycle_detection +} // namespace search + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + // [3, 4, 8, 5, 9, 1, 2, 6, 7, 4] return 4 + std::vector array1 = {3, 4, 8, 5, 9, 1, 2, 6, 7, 4}; + std::cout << "Test 1... "; + assert(search::cycle_detection::duplicateNumber(array1, array1.size()) == + 4); // here the duplicate number is 4 + std::cout << "passed" << std::endl; + + // 2nd test + // [1, 2, 3, 4, 2] return 2 + std::vector array2 = {1, 2, 3, 4, 2}; + std::cout << "Test 2... "; + assert(search::cycle_detection::duplicateNumber(array2, array2.size()) == + 2); // here the duplicate number is 2 + std::cout << "passed" << std::endl; + + // 3rd test + // [] return -1 + std::vector array3 = {}; + std::cout << "Test 3... "; + assert(search::cycle_detection::duplicateNumber(array3, array3.size()) == + -1); // since the input array is empty no duplicate number exists in + // this case + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From f34f93e77a25a987d19d9b582236b822d54e3452 Mon Sep 17 00:00:00 2001 From: Swastika Gupta <64654203+Swastyy@users.noreply.github.com> Date: Thu, 22 Jul 2021 00:52:16 +0530 Subject: [PATCH 19/22] feat: Add the Subarray Sum implementation (#1527) * Create subarray_sum.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for 0a293ece * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for f37f7b7c * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update subarray_sum.cpp * clang-format and clang-tidy fixes for 9b0b5f87 * Update backtracking/subarray_sum.cpp * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 047366a8 * Update subarray_sum.cpp * clang-format and clang-tidy fixes for 512b1887 * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal * fix: Apply suggestions from code review * docs: Apply suggestions from code review * clang-format and clang-tidy fixes for e6979047 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + backtracking/graph_coloring.cpp | 151 +++++------ backtracking/subarray_sum.cpp | 117 +++++++++ others/iterative_tree_traversals.cpp | 266 +++++++++++-------- sorting/random_pivot_quick_sort.cpp | 376 +++++++++++++++------------ 5 files changed, 549 insertions(+), 362 deletions(-) create mode 100644 backtracking/subarray_sum.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 7f2468bed..6f25fa66b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -8,6 +8,7 @@ * [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens_all_solution_optimised.cpp) * [Nqueen Print All Solutions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/nqueen_print_all_solutions.cpp) * [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/rat_maze.cpp) + * [Subarray Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subarray_sum.cpp) * [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp index 0f82a77bf..baa10ab46 100644 --- a/backtracking/graph_coloring.cpp +++ b/backtracking/graph_coloring.cpp @@ -1,22 +1,24 @@ /** * @file * @brief prints the assigned colors - * using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm + * using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring) + * algorithm * * @details - * In graph theory, graph coloring is a special case of graph labeling; - * it is an assignment of labels traditionally called "colors" to elements of a graph subject to certain constraints. - * In its simplest form, it is a way of coloring the vertices of a graph such that no two adjacent vertices are of the same color; - * this is called a vertex coloring. Similarly, an edge coloring assigns - * a color to each edge so that no two adjacent edges are of the same color, - * and a face coloring of a planar graph assigns a color to each face or + * In graph theory, graph coloring is a special case of graph labeling; + * it is an assignment of labels traditionally called "colors" to elements of a + * graph subject to certain constraints. In its simplest form, it is a way of + * coloring the vertices of a graph such that no two adjacent vertices are of + * the same color; this is called a vertex coloring. Similarly, an edge coloring + * assigns a color to each edge so that no two adjacent edges are of the same + * color, and a face coloring of a planar graph assigns a color to each face or * region so that no two faces that share a boundary have the same color. * * @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar) * @author [David Leal](https://github.com/Panquesito7) */ -#include #include +#include #include /** @@ -24,70 +26,72 @@ * @brief Backtracking algorithms */ namespace backtracking { - /** A utility function to print solution - * @tparam V number of vertices in the graph - * @param color array of colors assigned to the nodes - */ - template - void printSolution(const std::array & color) { - std::cout << "Following are the assigned colors" << std::endl; - for (auto &col : color) { - std::cout << col; - } - std::cout << std::endl; +/** A utility function to print solution + * @tparam V number of vertices in the graph + * @param color array of colors assigned to the nodes + */ +template +void printSolution(const std::array& color) { + std::cout << "Following are the assigned colors" << std::endl; + for (auto& col : color) { + std::cout << col; } + std::cout << std::endl; +} - /** A utility function to check if the current color assignment is safe for - * vertex v - * @tparam V number of vertices in the graph - * @param v index of graph vertex to check - * @param graph matrix of graph nonnectivity - * @param color vector of colors assigned to the graph nodes/vertices - * @param c color value to check for the node `v` - * @returns `true` if the color is safe to be assigned to the node - * @returns `false` if the color is not safe to be assigned to the node - */ - template - bool isSafe(int v, const std::array, V>& graph, const std::array & color, int c) { - for (int i = 0; i < V; i++) { - if (graph[v][i] && c == color[i]) { - return false; - } - } - return true; - } - - /** A recursive utility function to solve m coloring problem - * @tparam V number of vertices in the graph - * @param graph matrix of graph nonnectivity - * @param m number of colors - * @param [in,out] color description // used in,out to notify in documentation - * that this parameter gets modified by the function - * @param v index of graph vertex to check - */ - template - void graphColoring(const std::array, V>& graph, int m, std::array color, int v) { - // base case: - // If all vertices are assigned a color then return true - if (v == V) { - backtracking::printSolution(color); - return; - } - - // Consider this vertex v and try different colors - for (int c = 1; c <= m; c++) { - // Check if assignment of color c to v is fine - if (backtracking::isSafe(v, graph, color, c)) { - color[v] = c; - - // recur to assign colors to rest of the vertices - backtracking::graphColoring(graph, m, color, v + 1); - - // If assigning color c doesn't lead to a solution then remove it - color[v] = 0; - } +/** A utility function to check if the current color assignment is safe for + * vertex v + * @tparam V number of vertices in the graph + * @param v index of graph vertex to check + * @param graph matrix of graph nonnectivity + * @param color vector of colors assigned to the graph nodes/vertices + * @param c color value to check for the node `v` + * @returns `true` if the color is safe to be assigned to the node + * @returns `false` if the color is not safe to be assigned to the node + */ +template +bool isSafe(int v, const std::array, V>& graph, + const std::array& color, int c) { + for (int i = 0; i < V; i++) { + if (graph[v][i] && c == color[i]) { + return false; } } + return true; +} + +/** A recursive utility function to solve m coloring problem + * @tparam V number of vertices in the graph + * @param graph matrix of graph nonnectivity + * @param m number of colors + * @param [in,out] color description // used in,out to notify in documentation + * that this parameter gets modified by the function + * @param v index of graph vertex to check + */ +template +void graphColoring(const std::array, V>& graph, int m, + std::array color, int v) { + // base case: + // If all vertices are assigned a color then return true + if (v == V) { + backtracking::printSolution(color); + return; + } + + // Consider this vertex v and try different colors + for (int c = 1; c <= m; c++) { + // Check if assignment of color c to v is fine + if (backtracking::isSafe(v, graph, color, c)) { + color[v] = c; + + // recur to assign colors to rest of the vertices + backtracking::graphColoring(graph, m, color, v + 1); + + // If assigning color c doesn't lead to a solution then remove it + color[v] = 0; + } + } +} } // namespace backtracking /** @@ -102,15 +106,12 @@ int main() { // (0)---(1) const int V = 4; // number of vertices in the graph - std::array , V> graph = { - std::array ({0, 1, 1, 1}), - std::array ({1, 0, 1, 0}), - std::array ({1, 1, 0, 1}), - std::array ({1, 0, 1, 0}) - }; + std::array, V> graph = { + std::array({0, 1, 1, 1}), std::array({1, 0, 1, 0}), + std::array({1, 1, 0, 1}), std::array({1, 0, 1, 0})}; int m = 3; // Number of colors - std::array color{}; + std::array color{}; backtracking::graphColoring(graph, m, color, 0); return 0; diff --git a/backtracking/subarray_sum.cpp b/backtracking/subarray_sum.cpp new file mode 100644 index 000000000..8001d74cc --- /dev/null +++ b/backtracking/subarray_sum.cpp @@ -0,0 +1,117 @@ +/** + * @file + * @brief [Subset-sum](https://en.wikipedia.org/wiki/Subset_sum_problem) (only + * continuous subsets) problem + * @details We are given an array and a sum value. The algorithms find all + * the subarrays of that array with sum equal to the given sum and return such + * subarrays count. This approach will have \f$O(n)\f$ time complexity and + * \f$O(n)\f$ space complexity. NOTE: In this problem, we are only referring to + * the continuous subsets as subarrays everywhere. Subarrays can be created + * using deletion operation at the end of the front of an array only. The parent + * array is also counted in subarrays having 0 number of deletion operations. + * + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations +#include /// for unordered_map +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace subarray_sum + * @brief Functions for the [Subset + * sum](https://en.wikipedia.org/wiki/Subset_sum_problem) implementation + */ +namespace subarray_sum { +/** + * @brief The main function that implements the count of the subarrays + * @param sum is the required sum of any subarrays + * @param in_arr is the input array + * @returns count of the number of subsets with required sum + */ +uint64_t subarray_sum(int64_t sum, const std::vector &in_arr) { + int64_t nelement = in_arr.size(); + int64_t count_of_subset = 0; + int64_t current_sum = 0; + std::unordered_map + sumarray; // to store the subarrays count + // frequency having some sum value + + for (int64_t i = 0; i < nelement; i++) { + current_sum += in_arr[i]; + + if (current_sum == sum) { + count_of_subset++; + } + // If in case current_sum is greater than the required sum + if (sumarray.find(current_sum - sum) != sumarray.end()) { + count_of_subset += (sumarray[current_sum - sum]); + } + sumarray[current_sum]++; + } + return count_of_subset; +} +} // namespace subarray_sum +} // namespace backtracking + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::cout << "1st test "; + std::vector array1 = {-7, -3, -2, 5, 8}; // input array + assert( + backtracking::subarray_sum::subarray_sum(0, array1) == + 1); // first argument in subarray_sum function is the required sum and + // second is the input array, answer is the subarray {(-3,-2,5)} + std::cout << "passed" << std::endl; + + // 2nd test + std::cout << "2nd test "; + std::vector array2 = {1, 2, 3, 3}; + assert(backtracking::subarray_sum::subarray_sum(6, array2) == + 2); // here we are expecting 2 subsets which sum up to 6 i.e. + // {(1,2,3),(3,3)} + std::cout << "passed" << std::endl; + + // 3rd test + std::cout << "3rd test "; + std::vector array3 = {1, 1, 1, 1}; + assert(backtracking::subarray_sum::subarray_sum(1, array3) == + 4); // here we are expecting 4 subsets which sum up to 1 i.e. + // {(1),(1),(1),(1)} + std::cout << "passed" << std::endl; + + // 4rd test + std::cout << "4th test "; + std::vector array4 = {3, 3, 3, 3}; + assert(backtracking::subarray_sum::subarray_sum(6, array4) == + 3); // here we are expecting 3 subsets which sum up to 6 i.e. + // {(3,3),(3,3),(3,3)} + std::cout << "passed" << std::endl; + + // 5th test + std::cout << "5th test "; + std::vector array5 = {}; + assert(backtracking::subarray_sum::subarray_sum(6, array5) == + 0); // here we are expecting 0 subsets which sum up to 6 i.e. we + // cannot select anything from an empty array + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/others/iterative_tree_traversals.cpp b/others/iterative_tree_traversals.cpp index 6d0e7dc2e..0f9713b04 100644 --- a/others/iterative_tree_traversals.cpp +++ b/others/iterative_tree_traversals.cpp @@ -1,43 +1,45 @@ /** * @file - * @brief Iterative version of Preorder, Postorder, and preorder [Traversal of the Tree] - * (https://en.wikipedia.org/wiki/Tree_traversal) + * @brief Iterative version of Preorder, Postorder, and preorder [Traversal of + * the Tree] (https://en.wikipedia.org/wiki/Tree_traversal) * @author [Motasim](https://github.com/motasimmakki) * @details - * + * * ### Iterative Preorder Traversal of a tree * Create a Stack that will store the Node of Tree. * Push the root node into the stack. - * Save the root into the variabe named as current, and pop and elemnt from the stack. - * Store the data of current into the result array, and start traversing from it. - * Push both the child node of the current node into the stack, first right child then left child. - * Repeat the same set of steps untill the Stack becomes empty. - * And return the result array as the preorder traversal of a tree. - * + * Save the root into the variabe named as current, and pop and elemnt from the + * stack. Store the data of current into the result array, and start traversing + * from it. Push both the child node of the current node into the stack, first + * right child then left child. Repeat the same set of steps untill the Stack + * becomes empty. And return the result array as the preorder traversal of a + * tree. + * * ### Iterative Postorder Traversal of a tree * Create a Stack that will store the Node of Tree. * Push the root node into the stack. - * Save the root into the variabe named as current, and pop and elemnt from the stack. - * Store the data of current into the result array, and start traversing from it. - * Push both the child node of the current node into the stack, first left child then right child. - * Repeat the same set of steps untill the Stack becomes empty. - * Now reverse the result array and then return it to the calling function as a postorder traversal of a tree. - * + * Save the root into the variabe named as current, and pop and elemnt from the + * stack. Store the data of current into the result array, and start traversing + * from it. Push both the child node of the current node into the stack, first + * left child then right child. Repeat the same set of steps untill the Stack + * becomes empty. Now reverse the result array and then return it to the calling + * function as a postorder traversal of a tree. + * * ### Iterative Inorder Traversal of a tree * Create a Stack that will store the Node of Tree. * Push the root node into the stack. * Save the root into the variabe named as current. - * Now iterate and take the current to the extreme left of the tree by traversing only to its left. - * Pop the elemnt from the stack and assign it to the current. - * Store the data of current into the result array. - * Repeat the same set of steps until the Stack becomes empty or the current becomes NULL. - * And return the result array as the inorder traversal of a tree. + * Now iterate and take the current to the extreme left of the tree by + * traversing only to its left. Pop the elemnt from the stack and assign it to + * the current. Store the data of current into the result array. Repeat the same + * set of steps until the Stack becomes empty or the current becomes NULL. And + * return the result array as the inorder traversal of a tree. */ +#include /// for `reverse` +#include /// for `assert` #include /// for I/O operations #include /// for `stack` #include /// for `vector` -#include /// for `reverse` -#include /// for `assert` /** * @namespace others @@ -46,35 +48,44 @@ namespace others { /** * @namespace iterative_tree_traversals - * @brief Functions for the [Traversal of the Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm + * @brief Functions for the [Traversal of the + * Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm */ namespace iterative_tree_traversals { /** * @brief defines the structure of a node of the tree */ struct Node { - int64_t data = 0; ///< The value/key of the node. - struct Node *left; ///< struct pointer to left subtree. - struct Node *right; ///< struct pointer to right subtree. + int64_t data = 0; ///< The value/key of the node. + struct Node *left{}; ///< struct pointer to left subtree. + struct Node *right{}; ///< struct pointer to right subtree. }; /** * @brief defines the functions associated with the binary tree */ class BinaryTree { - public: - Node *createNewNode(int64_t); ///< function that will create new node for insertion. - std::vector preOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its preorder traversal. - std::vector postOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its postorder traversal. - std::vector inOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its inorder traversal. + public: + Node *createNewNode( + int64_t); ///< function that will create new node for insertion. + std::vector preOrderIterative( + Node *); ///< function that takes root of the tree as an argument, and + ///< returns its preorder traversal. + std::vector postOrderIterative( + Node *); ///< function that takes root of the tree as an argument, and + ///< returns its postorder traversal. + std::vector inOrderIterative( + Node *); ///< function that takes root of the tree as an argument, and + ///< returns its inorder traversal. }; /** - * @brief will allocate the memory for a node and, along the data and return the node. + * @brief will allocate the memory for a node and, along the data and return the + * node. * @param data value that a particular node will contain. - * @return pointer to the newly created node with assigned data. + * @return pointer to the newly created node with assigned data. */ -Node * BinaryTree::createNewNode(int64_t data) { +Node *BinaryTree::createNewNode(int64_t data) { Node *node = new Node(); node->data = data; node->left = node->right = nullptr; @@ -82,85 +93,91 @@ Node * BinaryTree::createNewNode(int64_t data) { } /** - * @brief preOrderIterative() function that will perform the preorder traversal iteratively, - * and return the result array that contain the preorder traversal of a tree. + * @brief preOrderIterative() function that will perform the preorder traversal + * iteratively, and return the result array that contain the preorder traversal + * of a tree. * @param root head/root node of a tree * @return result that is containing the preorder traversal of a tree */ -std::vector BinaryTree::preOrderIterative(Node *root) { - std::stack stack; ///< is used to find and traverse the child nodes. +std::vector BinaryTree::preOrderIterative(Node *root) { + std::stack + stack; ///< is used to find and traverse the child nodes. std::vector result; ///< list of values, sorted in pre-order. - + stack.push(root); - - while(!stack.empty()) { + + while (!stack.empty()) { result.push_back(stack.top()->data); Node *current = stack.top(); stack.pop(); - - if(current->right) { + + if (current->right) { stack.push(current->right); } - if(current->left) { + if (current->left) { stack.push(current->left); } } - + return result; } /** - * @brief postOrderIterative() function that will perform the postorder traversal iteratively, - * and return the result array that contain the postorder traversal of a tree. + * @brief postOrderIterative() function that will perform the postorder + * traversal iteratively, and return the result array that contain the postorder + * traversal of a tree. * @param root head/root node of a tree * @return result that is containing the postorder traversal of a tree */ -std::vector BinaryTree::postOrderIterative(Node *root) { - std::stack stack; ///< is used to find and traverse the child nodes. +std::vector BinaryTree::postOrderIterative(Node *root) { + std::stack + stack; ///< is used to find and traverse the child nodes. std::vector result; ///< List of values, sorted in post-order. - + stack.push(root); - - while(!stack.empty()) { + + while (!stack.empty()) { result.push_back(stack.top()->data); Node *current = stack.top(); stack.pop(); - - if(current->left) { + + if (current->left) { stack.push(current->left); } - if(current->right) { + if (current->right) { stack.push(current->right); } } reverse(result.begin(), result.end()); - + return result; } /** - * @brief inOrderIterative() function that will perform the inorder traversal iteratively, - * and return the result array that contain the inorder traversal of a tree. + * @brief inOrderIterative() function that will perform the inorder traversal + * iteratively, and return the result array that contain the inorder traversal + * of a tree. * @param root head/root node of a tree * @return result that is containing the inorder traversal of a tree */ std::vector BinaryTree::inOrderIterative(Node *root) { - std::stack stack; ///< is used to find and traverse the child nodes. + std::stack + stack; ///< is used to find and traverse the child nodes. std::vector result; ///< List of values, sorted in in-order. Node *current = root; - - while(!stack.empty() || current) { - while(current) { + + while (!stack.empty() || current) { + while (current) { stack.push(current); current = current->left; } current = stack.top(); - stack.pop(); - result.push_back(current->data); + stack.pop(); + result.push_back(current->data); current = current->right; - } + } return result; } } // namespace iterative_tree_traversals @@ -171,22 +188,25 @@ std::vector BinaryTree::inOrderIterative(Node *root) { * @param binaryTree instance of the BinaryTree class * @param root head/root node of a tree */ -static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{1, 2, 4, 5, 3}; - std::vector result; ///< result stores the preorder traversal of the binary tree + std::vector + result; ///< result stores the preorder traversal of the binary tree // Calling preOrderIterative() function by passing a root node, // and storing the preorder traversal in result. - result = binaryTree.preOrderIterative(root); + result = binaryTree.preOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing preorder. - std::cout<< "\nPreOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nPreOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } @@ -195,22 +215,25 @@ static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, othe * @param binaryTree instance of BinaryTree class * @param root head/root node of a tree */ -static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{4, 5, 2, 3, 1}; - std::vector result; ///< result stores the postorder traversal of the binary tree. + std::vector + result; ///< result stores the postorder traversal of the binary tree. // Calling postOrderIterative() function by passing a root node, // and storing the postorder traversal in result. result = binaryTree.postOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing postorder. - std::cout<< "\nPostOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nPostOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } @@ -219,22 +242,25 @@ static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, othe * @param binaryTree instance of BinaryTree class * @param root head/root node of a tree */ -static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{4, 2, 5, 1, 3}; - std::vector result; ///< result stores the inorder traversal of the binary tree. + std::vector + result; ///< result stores the inorder traversal of the binary tree. // Calling inOrderIterative() function by passing a root node, // and storing the inorder traversal in result. result = binaryTree.inOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing inorder. - std::cout<< "\nInOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nInOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } @@ -243,46 +269,53 @@ static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, othe * @param binaryTree instance of BinaryTree class * @param root head/root node of a tree */ -static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{-1, -2, -4, -5, -3}; - std::vector result; ///< result stores the preorder traversal of the binary tree + std::vector + result; ///< result stores the preorder traversal of the binary tree // Calling preOrderIterative() function by passing a root node, // and storing the preorder traversal in result. - result = binaryTree.preOrderIterative(root); + result = binaryTree.preOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing preorder. - std::cout<< "\nPreOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nPreOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } /** - * @brief Test the computed postorder with the actual postorder on negative value. + * @brief Test the computed postorder with the actual postorder on negative + * value. * @param binaryTree instance of BinaryTree class * @param root head/root node of a tree */ -static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{-4, -5, -2, -3, -1}; - std::vector result; ///< result stores the postorder traversal of the binary tree. + std::vector + result; ///< result stores the postorder traversal of the binary tree. // Calling postOrderIterative() function by passing a root node, // and storing the postorder traversal in result. result = binaryTree.postOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing postorder. - std::cout<< "\nPostOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nPostOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } @@ -291,22 +324,25 @@ static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, othe * @param binaryTree instance of BinaryTree class * @param root head/root node of a tree */ -static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){ +static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, + others::iterative_tree_traversals::Node *root) { std::vector actual_result{-4, -2, -5, -1, -3}; - std::vector result; ///< result stores the inorder traversal of the binary tree. + std::vector + result; ///< result stores the inorder traversal of the binary tree. // Calling inOrderIterative() function by passing a root node, // and storing the inorder traversal in result. result = binaryTree.inOrderIterative(root); // Self-testing the result using `assert` - for(int i = 0; i < result.size(); i++) + for (int i = 0; i < result.size(); i++) { assert(actual_result[i] == result[i]); + } // Printing the result storing inorder. - std::cout<< "\nInOrder Traversal Is : "<< std::endl; - for(auto i: result) { - std::cout<< i<< " "; + std::cout << "\nInOrder Traversal Is : " << std::endl; + for (auto i : result) { + std::cout << i << " "; } } @@ -316,7 +352,7 @@ static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, othe */ int main() { // Creating a tree with the following structure, - /* + /* 1 / \ 2 3 @@ -324,22 +360,24 @@ int main() { 4 5 */ - others::iterative_tree_traversals::BinaryTree binaryTree; ///< instace of BinaryTree, used to access its members functions. + others::iterative_tree_traversals::BinaryTree + binaryTree; ///< instace of BinaryTree, used to access its members + ///< functions. others::iterative_tree_traversals::Node *root = binaryTree.createNewNode(1); root->left = binaryTree.createNewNode(2); root->right = binaryTree.createNewNode(3); root->left->left = binaryTree.createNewNode(4); root->left->right = binaryTree.createNewNode(5); - std::cout<< "\n| Tests for positive data value |"<< std::endl; + std::cout << "\n| Tests for positive data value |" << std::endl; test1(binaryTree, root); // run preorder-iterative test - std::cout<< "\nPre-order test Passed!"<< std::endl; + std::cout << "\nPre-order test Passed!" << std::endl; test2(binaryTree, root); // run postorder-iterative test - std::cout<< "\nPost-order test Passed!"<< std::endl; + std::cout << "\nPost-order test Passed!" << std::endl; test3(binaryTree, root); // run inorder-iterative test - std::cout<< "\nIn-order test Passed!"<< std::endl; + std::cout << "\nIn-order test Passed!" << std::endl; // Modifying tree for negative values. root->data = -1; @@ -348,15 +386,15 @@ int main() { root->left->left->data = -4; root->left->right->data = -5; - std::cout<< "\n| Tests for negative data values |"<< std::endl; + std::cout << "\n| Tests for negative data values |" << std::endl; test4(binaryTree, root); // run preorder-iterative test on negative values - std::cout<< "\nPre-order test on-negative value Passed!"<< std::endl; + std::cout << "\nPre-order test on-negative value Passed!" << std::endl; test5(binaryTree, root); // run postorder-iterative test on negative values - std::cout<< "\nPost-order test on-negative value Passed!"<< std::endl; + std::cout << "\nPost-order test on-negative value Passed!" << std::endl; test6(binaryTree, root); // run inorder-iterative test on negative values - std::cout<< "\nIn-order test on-negative value Passed!"<< std::endl; + std::cout << "\nIn-order test on-negative value Passed!" << std::endl; return 0; } diff --git a/sorting/random_pivot_quick_sort.cpp b/sorting/random_pivot_quick_sort.cpp index 97892368f..a6ed19f12 100644 --- a/sorting/random_pivot_quick_sort.cpp +++ b/sorting/random_pivot_quick_sort.cpp @@ -1,44 +1,55 @@ /** * @file - * @brief Implementation of the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) algorithm. + * @brief Implementation of the [Random Pivot Quick + * Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) + * algorithm. * @details - * * A random pivot quick sort algorithm is pretty much same as quick sort with a difference of having a logic of - * selecting next pivot element from the input array. - * * Where in quick sort is fast, but still can give you the time complexity of O(n^2) in worst case. - * * To avoid hitting the time complexity of O(n^2), we use the logic of randomize the selection process of pivot - * element. + * * A random pivot quick sort algorithm is pretty much same as quick + * sort with a difference of having a logic of selecting next pivot element from + * the input array. + * * Where in quick sort is fast, but still can give you the time + * complexity of O(n^2) in worst case. + * * To avoid hitting the time complexity of O(n^2), we use the logic + * of randomize the selection process of pivot element. * * ### Logic - * * The logic is pretty simple, the only change is in the partitioning algorithm, which is selecting the - * pivot element. - * * Instead of selecting the last or the first element from array for pivot we use a random index to select - * pivot element. - * * This avoids hitting the O(n^2) time complexity in practical use cases. + * * The logic is pretty simple, the only change is in the + * partitioning algorithm, which is selecting the pivot element. + * * Instead of selecting the last or the first element from array + * for pivot we use a random index to select pivot element. + * * This avoids hitting the O(n^2) time complexity in practical + * use cases. * * ### Partition Logic - * * Partitions are done such as numbers lower than the "pivot" element is arranged on the left side of the "pivot", - * and number larger than the "pivot" element are arranged on the right part of the array. + * * Partitions are done such as numbers lower than the "pivot" + * element is arranged on the left side of the "pivot", and number larger than + * the "pivot" element are arranged on the right part of the array. * * ### Algorithm - * * Select the pivot element randomly using getRandomIndex() function from this namespace. - * * Initialize the pInd (partition index) from the start of the array. - * * Loop through the array from start to less than end. (from start to < end). - * (Inside the loop) :- - * * Check if the current element (arr[i]) is less than the pivot element in each iteration. - * * If current element in the iteration is less than the pivot element, - * then swap the elements at current index (i) and partition index (pInd) and increment the partition index by one. - * * At the end of the loop, swap the pivot element with partition index element. + * * Select the pivot element randomly using getRandomIndex() function + * from this namespace. + * * Initialize the pInd (partition index) from the start of the + * array. + * * Loop through the array from start to less than end. (from start + * to < end). (Inside the loop) :- + * * Check if the current element (arr[i]) is less than the + * pivot element in each iteration. + * * If current element in the iteration is less than the + * pivot element, then swap the elements at current index (i) and partition + * index (pInd) and increment the partition index by one. + * * At the end of the loop, swap the pivot element with partition + * index element. * * Return the partition index from the function. * * @author [Nitin Sharma](https://github.com/foo290) */ -#include /// for IO operations -#include /// for initializing random number generator -#include /// for assert -#include /// for std::is_sorted(), std::swap() +#include /// for std::is_sorted(), std::swap() #include /// for std::array -#include /// for returning multiple values form a function at once +#include /// for assert +#include /// for initializing random number generator +#include /// for IO operations +#include /// for returning multiple values form a function at once /** * @namespace sorting @@ -46,111 +57,120 @@ */ namespace sorting { /** - * @brief Functions for the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) implementation + * @brief Functions for the [Random Pivot Quick + * Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) + * implementation * @namespace random_pivot_quick_sort */ - namespace random_pivot_quick_sort { - /** - * @brief Utility function to print the array - * @tparam T size of the array - * @param arr array used to print its content - * @returns void - * */ - template - void showArray(std::array arr) { - for (int64_t i = 0; i < arr.size(); i++) { - std::cout << arr[i] << " "; - } - std::cout << std::endl; +namespace random_pivot_quick_sort { +/** + * @brief Utility function to print the array + * @tparam T size of the array + * @param arr array used to print its content + * @returns void + * */ +template +void showArray(std::array arr) { + for (int64_t i = 0; i < arr.size(); i++) { + std::cout << arr[i] << " "; + } + std::cout << std::endl; +} + +/** + * @brief Takes the start and end indices of an array and returns a random + * int64_teger between the range of those two for selecting pivot element. + * + * @param start The starting index. + * @param end The ending index. + * @returns int64_t A random number between start and end index. + * */ +int64_t getRandomIndex(int64_t start, int64_t end) { + srand(time(nullptr)); // Initialize random number generator. + int64_t randomPivotIndex = start + rand() % (end - start + 1); + return randomPivotIndex; +} + +/** + * @brief A partition function which handles the partition logic of quick sort. + * @tparam size size of the array to be passed as argument. + * @param start The start index of the passed array + * @param end The ending index of the passed array + * @returns std::tuple> A tuple of pivot + * index and pivot sorted array. + */ +template +std::tuple> partition( + std::array arr, int64_t start, int64_t end) { + int64_t pivot = arr[end]; // Randomly selected element will be here from + // caller function (quickSortRP()). + int64_t pInd = start; + + for (int64_t i = start; i < end; i++) { + if (arr[i] <= pivot) { + std::swap(arr[i], arr[pInd]); // swapping the elements from current + // index to pInd. + pInd++; } + } + std::swap(arr[pInd], + arr[end]); // swapping the pivot element to its sorted position + return std::make_tuple(pInd, arr); +} - /** - * @brief Takes the start and end indices of an array and returns a random int64_teger between the range of those two - * for selecting pivot element. - * - * @param start The starting index. - * @param end The ending index. - * @returns int64_t A random number between start and end index. - * */ - int64_t getRandomIndex(int64_t start, int64_t end) { - srand(time(nullptr)); // Initialize random number generator. - int64_t randomPivotIndex = start + rand() % (end - start + 1); - return randomPivotIndex; - } - - /** - * @brief A partition function which handles the partition logic of quick sort. - * @tparam size size of the array to be passed as argument. - * @param start The start index of the passed array - * @param end The ending index of the passed array - * @returns std::tuple> A tuple of pivot index and pivot sorted array. - */ - template - std::tuple> partition(std::array arr, int64_t start, int64_t end) { - - int64_t pivot = arr[end]; // Randomly selected element will be here from caller function (quickSortRP()). - int64_t pInd = start; - - for (int64_t i = start; i < end; i++) { - if (arr[i] <= pivot) { - std::swap(arr[i], arr[pInd]); // swapping the elements from current index to pInd. - pInd++; - } - } - std::swap(arr[pInd], arr[end]); // swapping the pivot element to its sorted position - return std::make_tuple(pInd, arr); - } - - /** - * @brief Random pivot quick sort function. This function is the starting point of the algorithm. - * @tparam size size of the array to be passed as argument. - * @param start The start index of the passed array - * @param end The ending index of the passed array - * @returns std::array A fully sorted array in ascending order. - */ - template - std::array quickSortRP(std::array arr, int64_t start, int64_t end) { - if (start < end) { - - int64_t randomIndex = getRandomIndex(start, end); - - // switching the pivot with right most bound. - std::swap(arr[end], arr[randomIndex]); - - int64_t pivotIndex = 0; - // getting pivot index and pivot sorted array. - std::tie(pivotIndex, arr) = partition(arr, start, end); - - // Recursively calling - std::array rightSortingLeft = quickSortRP(arr, start, pivotIndex - 1); - std::array full_sorted = quickSortRP(rightSortingLeft, pivotIndex + 1, end); - arr = full_sorted; - } - return arr; - } - - /** - * @brief A function utility to generate unsorted array of given size and range. - * @tparam size Size of the output array. - * @param from Stating of the range. - * @param to Ending of the range. - * @returns std::array Unsorted array of specified size. - * */ - template - std::array generateUnsortedArray(int64_t from, int64_t to) { - srand(time(nullptr)); - std::array unsortedArray{}; - assert(from < to); - int64_t i = 0; - while (i < size) { - int64_t randomNum = from + rand() % (to - from + 1); - if (randomNum) { - unsortedArray[i] = randomNum; - i++; - } - } - return unsortedArray; +/** + * @brief Random pivot quick sort function. This function is the starting point + * of the algorithm. + * @tparam size size of the array to be passed as argument. + * @param start The start index of the passed array + * @param end The ending index of the passed array + * @returns std::array A fully sorted array in ascending order. + */ +template +std::array quickSortRP(std::array arr, + int64_t start, int64_t end) { + if (start < end) { + int64_t randomIndex = getRandomIndex(start, end); + + // switching the pivot with right most bound. + std::swap(arr[end], arr[randomIndex]); + + int64_t pivotIndex = 0; + // getting pivot index and pivot sorted array. + std::tie(pivotIndex, arr) = partition(arr, start, end); + + // Recursively calling + std::array rightSortingLeft = + quickSortRP(arr, start, pivotIndex - 1); + std::array full_sorted = + quickSortRP(rightSortingLeft, pivotIndex + 1, end); + arr = full_sorted; + } + return arr; +} + +/** + * @brief A function utility to generate unsorted array of given size and range. + * @tparam size Size of the output array. + * @param from Stating of the range. + * @param to Ending of the range. + * @returns std::array Unsorted array of specified size. + * */ +template +std::array generateUnsortedArray(int64_t from, int64_t to) { + srand(time(nullptr)); + std::array unsortedArray{}; + assert(from < to); + int64_t i = 0; + while (i < size) { + int64_t randomNum = from + rand() % (to - from + 1); + if (randomNum) { + unsortedArray[i] = randomNum; + i++; } + } + return unsortedArray; +} } // namespace random_pivot_quick_sort } // namespace sorting @@ -159,23 +179,23 @@ namespace sorting { * @brief a class containing the necessary test cases */ class TestCases { -private: + private: /** - * @brief A function to print64_t given message on console. - * @tparam T Type of the given message. - * @returns void - * */ - template + * @brief A function to print64_t given message on console. + * @tparam T Type of the given message. + * @returns void + * */ + template void log(T msg) { // It's just to avoid writing cout and endl std::cout << "[TESTS] : ---> " << msg << std::endl; } -public: + public: /** - * @brief Executes test cases - * @returns void - * */ + * @brief Executes test cases + * @returns void + * */ void runTests() { log("Running Tests..."); @@ -188,24 +208,25 @@ public: } /** - * @brief A test case with single input - * @returns void - * */ + * @brief A test case with single input + * @returns void + * */ void testCase_1() { const int64_t inputSize = 1; - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); log("This is test case 1 for Random Pivot Quick Sort Algorithm : "); log("Description:"); log(" EDGE CASE : Only contains one element"); - std::array unsorted_arr{2}; + std::array unsorted_arr{2}; int64_t start = 0; - int64_t end = unsorted_arr.size() - 1; // length - 1 + int64_t end = unsorted_arr.size() - 1; // length - 1 log("Running algorithm of data of length 50 ..."); - std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( - unsorted_arr, start, end - ); + std::array sorted_arr = + sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start, + end); log("Algorithm finished!"); log("Checking assert expression..."); @@ -213,28 +234,32 @@ public: log("Assertion check passed!"); log("[PASS] : TEST CASE 1 PASS!"); - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); } /** - * @brief A test case with input array of length 500 - * @returns void - * */ + * @brief A test case with input array of length 500 + * @returns void + * */ void testCase_2() { const int64_t inputSize = 500; - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); log("Description:"); log(" BIG INPUT : Contains 500 elements and repeated elements"); log("This is test case 2 for Random Pivot Quick Sort Algorithm : "); - std::array unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray(1, 10000); + std::array unsorted_arr = + sorting::random_pivot_quick_sort::generateUnsortedArray( + 1, 10000); int64_t start = 0; - int64_t end = unsorted_arr.size() - 1; // length - 1 + int64_t end = unsorted_arr.size() - 1; // length - 1 log("Running algorithm of data of length 500 ..."); - std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( - unsorted_arr, start, end - ); + std::array sorted_arr = + sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start, + end); log("Algorithm finished!"); log("Checking assert expression..."); @@ -242,28 +267,32 @@ public: log("Assertion check passed!"); log("[PASS] : TEST CASE 2 PASS!"); - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); } /** - * @brief A test case with array of length 1000. - * @returns void - * */ + * @brief A test case with array of length 1000. + * @returns void + * */ void testCase_3() { const int64_t inputSize = 1000; - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); log("This is test case 3 for Random Pivot Quick Sort Algorithm : "); log("Description:"); log(" LARGE INPUT : Contains 1000 elements and repeated elements"); - std::array unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray(1, 10000); + std::array unsorted_arr = + sorting::random_pivot_quick_sort::generateUnsortedArray( + 1, 10000); int64_t start = 0; - int64_t end = unsorted_arr.size() - 1; // length - 1 + int64_t end = unsorted_arr.size() - 1; // length - 1 log("Running algorithm..."); - std::array sorted_arr = sorting::random_pivot_quick_sort::quickSortRP( - unsorted_arr, start, end - ); + std::array sorted_arr = + sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start, + end); log("Algorithm finished!"); log("Checking assert expression..."); @@ -271,11 +300,11 @@ public: log("Assertion check passed!"); log("[PASS] : TEST CASE 3 PASS!"); - log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + "~"); } }; - /** * @brief Self-test implementations * @returns void @@ -292,17 +321,18 @@ static void test() { * @returns 0 on exit */ int main(int argc, char *argv[]) { - test(); // Executes various test cases. + test(); // Executes various test cases. const int64_t inputSize = 10; - std::array unsorted_array = sorting::random_pivot_quick_sort::generateUnsortedArray(50, 1000); + std::array unsorted_array = + sorting::random_pivot_quick_sort::generateUnsortedArray( + 50, 1000); std::cout << "Unsorted array is : " << std::endl; sorting::random_pivot_quick_sort::showArray(unsorted_array); - std::array sorted_array = sorting::random_pivot_quick_sort::quickSortRP( - unsorted_array, 0, - unsorted_array.size() - 1 - ); + std::array sorted_array = + sorting::random_pivot_quick_sort::quickSortRP( + unsorted_array, 0, unsorted_array.size() - 1); std::cout << "Sorted array is : " << std::endl; sorting::random_pivot_quick_sort::showArray(sorted_array); return 0; From 5d34de836e257eda95bc6b452436283a82902eae Mon Sep 17 00:00:00 2001 From: David Leal Date: Thu, 22 Jul 2021 11:40:10 -0500 Subject: [PATCH 20/22] feat: Convert all issue templates into issue forms (#1545) * feat: Convert all issue templates into issue... ...forms. Also disables blank issues and adds an `Other` template for generic issues but no blank issues. * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.md | 33 ----------- .github/ISSUE_TEMPLATE/bug_report.yml | 64 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/ISSUE_TEMPLATE/feature_request.md | 20 ------- .github/ISSUE_TEMPLATE/feature_request.yml | 38 +++++++++++++ .github/ISSUE_TEMPLATE/other.yml | 22 ++++++++ DIRECTORY.md | 1 + 7 files changed, 126 insertions(+), 53 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/other.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6506be174..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve. Report bugs found while using the project -title: "[BUG]" -labels: bug -assignees: '' - ---- - - - -## Description - - -## Expected Behavior - - -## Actual Behavior - - -## Possible Fix - - -## Steps to Reproduce - - -1. -2. -3. -4. - -## Context - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..89ea09cb2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,64 @@ +name: Bug report +description: Create a report to help us improve. Report bugs found while using the project +title: "[BUG]" +labels: [bug] +body: + - type: markdown + attributes: + value: "Provide a general summary of the issue in the Title above" + - type: textarea + id: description + attributes: + label: Description + description: Provide a general summary of the issue in the Title above + validations: + required: true + - type: input + id: expectedbhv + attributes: + label: Expected behavior + description: Tell us what should happen + validations: + required: true + - type: input + id: actualbhv + attributes: + label: Actual behavior + description: Tell us what happens instead + validations: + required: true + - type: input + id: possiblefix + attributes: + label: Possible fix + description: Not obligatory, but suggest a fix or reason for the bug + validations: + required: false + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: | + Provide a link to a live example, or an unambiguous set of steps to + reproduce this bug. Include code to reproduce, if relevant + placeholder: | + 1. + 2. + 3. + 4. + validations: + required: true + - type: textarea + id: context + attributes: + label: Context + description: How has this bug affected you? What were you trying to accomplish? + validations: + required: true + - type: textarea + id: extrainformation + attributes: + label: Additional information + description: Is there anything else we should know about this bug? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3ba13e0ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 2d1696261..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest features, propose improvements, discuss new ideas. -title: "[FEATURE]" -labels: enhancement -assignees: '' - ---- - - - -## Detailed Description - - -## Context - - - -## Possible Implementation - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..46cc9a391 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,38 @@ +name: Feature request +description: Suggest features, propose improvements, discuss new ideas. +title: "[FEATURE]" +labels: [enhancement] +body: + - type: markdown + attributes: + value: Provide a general summary of the issue in the Title above + - type: textarea + id: description + attributes: + label: Detailed description + description: Provide a detailed description of the change or addition you are proposing + validations: + required: true + - type: textarea + id: context + attributes: + label: Context + description: | + Why is this change important to you? How would you use it? + How can it benefit other users? + validations: + required: true + - type: textarea + id: possibleimpl + attributes: + label: Possible implementation + description: Not obligatory, but suggest an idea for implementing addition or change + validations: + required: false + - type: textarea + id: extrainformation + attributes: + label: Additional information + description: Is there anything else we should know about this feature? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml new file mode 100644 index 000000000..901d227ba --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.yml @@ -0,0 +1,22 @@ +name: Other +description: Use this for any other issues. Do NOT create blank issues +title: "[OTHER]" +labels: [triage] +body: + - type: markdown + attributes: + value: "# Other issue" + - type: textarea + id: issuedescription + attributes: + label: What would you like to share? + description: Provide a clear and concise explanation of your issue. + validations: + required: true + - type: textarea + id: extrainfo + attributes: + label: Additional information + description: Is there anything else we should know about this issue? + validations: + required: false diff --git a/DIRECTORY.md b/DIRECTORY.md index 6f25fa66b..e89e9c7af 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -267,6 +267,7 @@ * [Binary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/binary_search.cpp) * [Exponential Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/exponential_search.cpp) * [Fibonacci Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/fibonacci_search.cpp) + * [Floyd Cycle Detection Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/floyd_cycle_detection_algo.cpp) * [Hash Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/hash_search.cpp) * [Interpolation Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/interpolation_search.cpp) * [Interpolation Search2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/interpolation_search2.cpp) From f9a1acd4c3ffebbb6f4b183869de1cb7fb508c17 Mon Sep 17 00:00:00 2001 From: codingbbq <47356490+codingbbq@users.noreply.github.com> Date: Thu, 22 Jul 2021 23:38:28 +0530 Subject: [PATCH 21/22] Issue #1536 - [BUG] check_prime.cpp returns incorrect output for 9 (#1537) Co-authored-by: Idrish Laxmidhar Co-authored-by: Vishal Sharma Co-authored-by: David Leal --- math/check_prime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/check_prime.cpp b/math/check_prime.cpp index ea4e6d52d..d68325d56 100644 --- a/math/check_prime.cpp +++ b/math/check_prime.cpp @@ -29,7 +29,7 @@ bool is_prime(T num) { return 0; } if (num >= 3) { - for (T i = 3; (i * i) < (num); i = (i + 2)) { + for (T i = 3; (i * i) <= (num); i = (i + 2)) { if ((num % i) == 0) { result = false; break; From a6bd93653036e3487ea4f0fcdbdeaca30b0d1c9a Mon Sep 17 00:00:00 2001 From: Panquesito7 Date: Sun, 25 Jul 2021 19:06:58 +0000 Subject: [PATCH 22/22] test