From 4d884b0dc7514b1389056f53be18dacb8c452b33 Mon Sep 17 00:00:00 2001 From: Alvin Philips Date: Mon, 25 Oct 2021 21:35:11 +0530 Subject: [PATCH 1/6] fix: Union of two arrays (#1797) * Create reverse_binary_tree.cpp * Added documentation Added Documentation for the level_order_traversal() function, and implemented a print() function to display the tree to STDOUT * Added documentation * Renamed tests to test * Fixed issue with incorrect using statement * updating DIRECTORY.md * clang-format and clang-tidy fixes for fb86292d * Added Test cases * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Changed int to int64_t * Updated documentation wording * Added reference to intersection of two arrays Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- operations_on_datastructures/union_of_two_arrays.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/operations_on_datastructures/union_of_two_arrays.cpp b/operations_on_datastructures/union_of_two_arrays.cpp index d2a621440..8fd75bde7 100644 --- a/operations_on_datastructures/union_of_two_arrays.cpp +++ b/operations_on_datastructures/union_of_two_arrays.cpp @@ -7,6 +7,7 @@ * in the first array, combined with all of the unique elements of a second * array. This implementation uses ordered arrays, and an algorithm to correctly * order them and return the result as a new array (vector). + * @see intersection_of_two_arrays.cpp * @author [Alvin](https://github.com/polarvoid) */ From b3a0070a741809a46f45831688cd72b56c073907 Mon Sep 17 00:00:00 2001 From: Lajat5 <64376519+Lazeeez@users.noreply.github.com> Date: Mon, 25 Oct 2021 23:47:33 +0530 Subject: [PATCH 2/6] feat: Reworked/updated sorting/selection_sort.cpp. (#1613) * Reworked selection_sort.cpp with fixes. * Added Recursive implementation for tree traversing * Fix #2 * Delete recursive_tree_traversals.cpp * Update selection_sort.cpp * Changes done in selection_sort_iterative.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for 4681e4f7 * Update sorting/selection_sort_iterative.cpp Co-authored-by: David Leal * Update sorting/selection_sort_iterative.cpp Co-authored-by: David Leal * Update selection_sort_iterative.cpp * Update sorting/selection_sort_iterative.cpp Co-authored-by: David Leal * Update sorting/selection_sort_iterative.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for ca2a7c64 * Finished changes requested by ayaankhan98. * Reworked on changes. * clang-format and clang-tidy fixes for f79b79b7 * Corrected errors. * Fix #2 * Fix #3 * Major Fix #3 * clang-format and clang-tidy fixes for 79341db8 * clang-format and clang-tidy fixes for 9bdf2ce4 * Update selection_sort_iterative.cpp * clang-format and clang-tidy fixes for 9833d7a7 * clang-format and clang-tidy fixes for b7726460 Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> --- DIRECTORY.md | 2 +- bit_manipulation/count_of_set_bits.cpp | 21 ++-- ciphers/atbash_cipher.cpp | 5 +- data_structures/dsu_path_compression.cpp | 2 +- data_structures/stack_using_queue.cpp | 154 +++++++++++------------ math/area.cpp | 55 ++++---- math/integral_approximation2.cpp | 128 +++++++++++-------- range_queries/segtree.cpp | 4 +- sorting/selection_sort.cpp | 33 ----- sorting/selection_sort_iterative.cpp | 126 +++++++++++++++++++ 10 files changed, 322 insertions(+), 208 deletions(-) delete mode 100644 sorting/selection_sort.cpp create mode 100644 sorting/selection_sort_iterative.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index a691a652b..0c504e8c6 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -338,7 +338,7 @@ * [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) + * [Selection Sort Iterative](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort_iterative.cpp) * [Selection Sort Recursive](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort_recursive.cpp) * [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort.cpp) * [Shell Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort2.cpp) diff --git a/bit_manipulation/count_of_set_bits.cpp b/bit_manipulation/count_of_set_bits.cpp index 497346a53..f2d802061 100644 --- a/bit_manipulation/count_of_set_bits.cpp +++ b/bit_manipulation/count_of_set_bits.cpp @@ -5,7 +5,8 @@ * integer. * * @details - * We are given an integer number. We need to calculate the number of set bits in it. + * We are given an integer number. We need to calculate the number of set bits + * in it. * * A binary number consists of two digits. They are 0 & 1. Digit 1 is known as * set bit in computer terms. @@ -15,7 +16,7 @@ * @author [Prashant Thakur](https://github.com/prashant-th18) */ #include /// for assert -#include /// for IO operations +#include /// for IO operations /** * @namespace bit_manipulation * @brief Bit manipulation algorithms @@ -33,21 +34,21 @@ namespace count_of_set_bits { * @param n is the number whose set bit will be counted * @returns total number of set-bits in the binary representation of number `n` */ -std::uint64_t countSetBits(std :: int64_t n) { // int64_t is preferred over int so that - // no Overflow can be there. +std::uint64_t countSetBits( + std ::int64_t n) { // int64_t is preferred over int so that + // no Overflow can be there. - int count = 0; // "count" variable is used to count number of set-bits('1') in - // binary representation of number 'n' - while (n != 0) - { + int count = 0; // "count" variable is used to count number of set-bits('1') + // in binary representation of number 'n' + while (n != 0) { ++count; n = (n & (n - 1)); } return count; // Why this algorithm is better than the standard one? // Because this algorithm runs the same number of times as the number of - // set-bits in it. Means if my number is having "3" set bits, then this while loop - // will run only "3" times!! + // set-bits in it. Means if my number is having "3" set bits, then this + // while loop will run only "3" times!! } } // namespace count_of_set_bits } // namespace bit_manipulation diff --git a/ciphers/atbash_cipher.cpp b/ciphers/atbash_cipher.cpp index 04c330598..4f0d793f2 100644 --- a/ciphers/atbash_cipher.cpp +++ b/ciphers/atbash_cipher.cpp @@ -22,7 +22,8 @@ */ namespace ciphers { /** \namespace atbash - * \brief Functions for the [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + * \brief Functions for the [Atbash + * Cipher](https://en.wikipedia.org/wiki/Atbash) implementation */ namespace atbash { std::map atbash_cipher_map = { @@ -43,7 +44,7 @@ std::map atbash_cipher_map = { * @param text Plaintext to be encrypted * @returns encoded or decoded string */ -std::string atbash_cipher(std::string text) { +std::string atbash_cipher(const std::string& text) { std::string result; for (char letter : text) { result += atbash_cipher_map[letter]; diff --git a/data_structures/dsu_path_compression.cpp b/data_structures/dsu_path_compression.cpp index a5c0aec33..022e632a7 100644 --- a/data_structures/dsu_path_compression.cpp +++ b/data_structures/dsu_path_compression.cpp @@ -184,7 +184,7 @@ static void test1() { * @returns void */ static void test2() { - // the minimum, maximum, and size of the set + // the minimum, maximum, and size of the set uint64_t n = 10; ///< number of items dsu d(n + 1); ///< object of class disjoint sets // set 1 diff --git a/data_structures/stack_using_queue.cpp b/data_structures/stack_using_queue.cpp index 54a81a135..bd6a60e2b 100644 --- a/data_structures/stack_using_queue.cpp +++ b/data_structures/stack_using_queue.cpp @@ -3,13 +3,14 @@ * @details * Using 2 Queues inside the Stack class, we can easily implement Stack * data structure with heavy computation in push function. - * - * References used: [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) + * + * References used: + * [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) * @author [tushar2407](https://github.com/tushar2407) */ -#include /// for IO operations -#include /// for queue data structure -#include /// for assert +#include /// for assert +#include /// for IO operations +#include /// for queue data structure /** * @namespace data_strcutres @@ -18,66 +19,59 @@ namespace data_structures { /** * @namespace stack_using_queue - * @brief Functions for the [Stack Using Queue](https://www.studytonight.com/data-structures/stack-using-queue) implementation + * @brief Functions for the [Stack Using + * Queue](https://www.studytonight.com/data-structures/stack-using-queue) + * implementation */ namespace stack_using_queue { +/** + * @brief Stack Class implementation for basic methods of Stack Data Structure. + */ +struct Stack { + std::queue main_q; ///< stores the current state of the stack + std::queue auxiliary_q; ///< used to carry out intermediate + ///< operations to implement stack + uint32_t current_size = 0; ///< stores the current size of the stack + /** - * @brief Stack Class implementation for basic methods of Stack Data Structure. + * Returns the top most element of the stack + * @returns top element of the queue */ - struct Stack - { - std::queue main_q; ///< stores the current state of the stack - std::queue auxiliary_q; ///< used to carry out intermediate operations to implement stack - uint32_t current_size = 0; ///< stores the current size of the stack - - /** - * Returns the top most element of the stack - * @returns top element of the queue - */ - int top() - { - return main_q.front(); - } + int top() { return main_q.front(); } - /** - * @brief Inserts an element to the top of the stack. - * @param val the element that will be inserted into the stack - * @returns void - */ - void push(int val) - { - auxiliary_q.push(val); - while(!main_q.empty()) - { - auxiliary_q.push(main_q.front()); - main_q.pop(); - } - swap(main_q, auxiliary_q); - current_size++; - } - - /** - * @brief Removes the topmost element from the stack - * @returns void - */ - void pop() - { - if(main_q.empty()) { - return; - } + /** + * @brief Inserts an element to the top of the stack. + * @param val the element that will be inserted into the stack + * @returns void + */ + void push(int val) { + auxiliary_q.push(val); + while (!main_q.empty()) { + auxiliary_q.push(main_q.front()); main_q.pop(); - current_size--; } + swap(main_q, auxiliary_q); + current_size++; + } - /** - * @brief Utility function to return the current size of the stack - * @returns current size of stack - */ - int size() - { - return current_size; + /** + * @brief Removes the topmost element from the stack + * @returns void + */ + void pop() { + if (main_q.empty()) { + return; } - }; + main_q.pop(); + current_size--; + } + + /** + * @brief Utility function to return the current size of the stack + * @returns current size of stack + */ + int size() { return current_size; } +}; } // namespace stack_using_queue } // namespace data_structures @@ -85,30 +79,29 @@ namespace stack_using_queue { * @brief Self-test implementations * @returns void */ -static void test() -{ +static void test() { data_structures::stack_using_queue::Stack s; - s.push(1); /// insert an element into the stack - s.push(2); /// insert an element into the stack - s.push(3); /// insert an element into the stack - - assert(s.size()==3); /// size should be 3 - - assert(s.top()==3); /// topmost element in the stack should be 3 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==2); /// topmost element in the stack should now be 2 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==1); - - s.push(5); /// insert an element into the stack - assert(s.top()==5); /// topmost element in the stack should now be 5 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==1); /// topmost element in the stack should now be 1 - - assert(s.size()==1); /// size should be 1 + s.push(1); /// insert an element into the stack + s.push(2); /// insert an element into the stack + s.push(3); /// insert an element into the stack + + assert(s.size() == 3); /// size should be 3 + + assert(s.top() == 3); /// topmost element in the stack should be 3 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 2); /// topmost element in the stack should now be 2 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); + + s.push(5); /// insert an element into the stack + assert(s.top() == 5); /// topmost element in the stack should now be 5 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); /// topmost element in the stack should now be 1 + + assert(s.size() == 1); /// size should be 1 } /** @@ -119,8 +112,7 @@ static void test() * declared above. * @returns 0 on exit */ -int main() -{ +int main() { test(); // run self-test implementations return 0; } diff --git a/math/area.cpp b/math/area.cpp index 6983cf3e4..691fe91f0 100644 --- a/math/area.cpp +++ b/math/area.cpp @@ -1,17 +1,19 @@ /** * @file - * @brief Implementations for the [area](https://en.wikipedia.org/wiki/Area) of various shapes - * @details The area of a shape is the amount of 2D space it takes up. - * All shapes have a formula to get the area of any given shape. + * @brief Implementations for the [area](https://en.wikipedia.org/wiki/Area) of + * various shapes + * @details The area of a shape is the amount of 2D space it takes up. + * All shapes have a formula to get the area of any given shape. * These implementations support multiple return types. - * + * * @author [Focusucof](https://github.com/Focusucof) */ #define _USE_MATH_DEFINES -#include /// for M_PI definition and pow() -#include /// for uint16_t datatype -#include /// for IO operations #include /// for assert +#include /// for M_PI definition and pow() +#include +#include /// for uint16_t datatype +#include /// for IO operations /** * @namespace math @@ -115,25 +117,25 @@ T cylinder_surface_area(T radius, T height) { */ static void test() { // I/O variables for testing - uint16_t int_length; // 16 bit integer length input - uint16_t int_width; // 16 bit integer width input - uint16_t int_base; // 16 bit integer base input - uint16_t int_height; // 16 bit integer height input - uint16_t int_expected; // 16 bit integer expected output - uint16_t int_area; // 16 bit integer output + uint16_t int_length = 0; // 16 bit integer length input + uint16_t int_width = 0; // 16 bit integer width input + uint16_t int_base = 0; // 16 bit integer base input + uint16_t int_height = 0; // 16 bit integer height input + uint16_t int_expected = 0; // 16 bit integer expected output + uint16_t int_area = 0; // 16 bit integer output - float float_length; // float length input - float float_expected; // float expected output - float float_area; // float output + float float_length = NAN; // float length input + float float_expected = NAN; // float expected output + float float_area = NAN; // float output - double double_length; // double length input - double double_width; // double width input - double double_radius; // double radius input - double double_height; // double height input - double double_expected; // double expected output - double double_area; // double output + double double_length = NAN; // double length input + double double_width = NAN; // double width input + double double_radius = NAN; // double radius input + double double_height = NAN; // double height input + double double_expected = NAN; // double expected output + double double_area = NAN; // double output - // 1st test + // 1st test int_length = 5; int_expected = 25; int_area = math::square_area(int_length); @@ -201,7 +203,9 @@ static void test() { // 6th test double_radius = 6; - double_expected = 113.09733552923255; // rounded down because the double datatype truncates after 14 decimal places + double_expected = + 113.09733552923255; // rounded down because the double datatype + // truncates after 14 decimal places double_area = math::circle_area(double_radius); std::cout << "AREA OF A CIRCLE" << std::endl; @@ -239,7 +243,8 @@ static void test() { // 9th test double_radius = 10.0; - double_expected = 1256.6370614359172; // rounded down because the whole value gets truncated + double_expected = 1256.6370614359172; // rounded down because the whole + // value gets truncated double_area = math::sphere_surface_area(double_radius); std::cout << "SURFACE AREA OF A SPHERE" << std::endl; diff --git a/math/integral_approximation2.cpp b/math/integral_approximation2.cpp index 706672d12..eed605e03 100644 --- a/math/integral_approximation2.cpp +++ b/math/integral_approximation2.cpp @@ -1,29 +1,34 @@ /** * @file - * @brief [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) + * @brief [Monte Carlo + * Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) * * @details - * In mathematics, Monte Carlo integration is a technique for numerical integration using random numbers. - * It is a particular Monte Carlo method that numerically computes a definite integral. - * While other algorithms usually evaluate the integrand at a regular grid, Monte Carlo randomly chooses points at which the integrand is evaluated. - * This method is particularly useful for higher-dimensional integrals. + * In mathematics, Monte Carlo integration is a technique for numerical + * integration using random numbers. It is a particular Monte Carlo method that + * numerically computes a definite integral. While other algorithms usually + * evaluate the integrand at a regular grid, Monte Carlo randomly chooses points + * at which the integrand is evaluated. This method is particularly useful for + * higher-dimensional integrals. * * This implementation supports arbitrary pdfs. - * These pdfs are sampled using the [Metropolis-Hastings algorithm](https://en.wikipedia.org/wiki/Metropolis–Hastings_algorithm). - * This can be swapped out by every other sampling techniques for example the inverse method. - * Metropolis-Hastings was chosen because it is the most general and can also be extended for a higher dimensional sampling space. + * These pdfs are sampled using the [Metropolis-Hastings + * algorithm](https://en.wikipedia.org/wiki/Metropolis–Hastings_algorithm). This + * can be swapped out by every other sampling techniques for example the inverse + * method. Metropolis-Hastings was chosen because it is the most general and can + * also be extended for a higher dimensional sampling space. * * @author [Domenic Zingsheim](https://github.com/DerAndereDomenic) */ -#define _USE_MATH_DEFINES /// for M_PI on windows -#include /// for math functions -#include /// for fixed size data types -#include /// for time to initialize rng -#include /// for function pointers -#include /// for std::cout -#include /// for random number generation -#include /// for std::vector +#define _USE_MATH_DEFINES /// for M_PI on windows +#include /// for math functions +#include /// for fixed size data types +#include /// for time to initialize rng +#include /// for function pointers +#include /// for std::cout +#include /// for random number generation +#include /// for std::vector /** * @namespace math @@ -32,25 +37,34 @@ namespace math { /** * @namespace monte_carlo - * @brief Functions for the [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) implementation + * @brief Functions for the [Monte Carlo + * Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) + * implementation */ namespace monte_carlo { -using Function = std::function; /// short-hand for std::functions used in this implementation +using Function = std::function; /// short-hand for std::functions used in this implementation /** * @brief Generate samples according to some pdf - * @details This function uses Metropolis-Hastings to generate random numbers. It generates a sequence of random numbers by using a markov chain. - * Therefore, we need to define a start_point and the number of samples we want to generate. - * Because the first samples generated by the markov chain may not be distributed according to the given pdf, one can specify how many samples + * @details This function uses Metropolis-Hastings to generate random numbers. + * It generates a sequence of random numbers by using a markov chain. Therefore, + * we need to define a start_point and the number of samples we want to + * generate. Because the first samples generated by the markov chain may not be + * distributed according to the given pdf, one can specify how many samples * should be discarded before storing samples. * @param start_point The starting point of the markov chain * @param pdf The pdf to sample * @param num_samples The number of samples to generate * @param discard How many samples should be discarded at the start - * @returns A vector of size num_samples with samples distributed according to the pdf + * @returns A vector of size num_samples with samples distributed according to + * the pdf */ -std::vector generate_samples(const double& start_point, const Function& pdf, const uint32_t& num_samples, const uint32_t& discard = 100000) { +std::vector generate_samples(const double& start_point, + const Function& pdf, + const uint32_t& num_samples, + const uint32_t& discard = 100000) { std::vector samples; samples.reserve(num_samples); @@ -61,19 +75,19 @@ std::vector generate_samples(const double& start_point, const Function& std::normal_distribution normal(0.0, 1.0); generator.seed(time(nullptr)); - for(uint32_t t = 0; t < num_samples + discard; ++t) { + for (uint32_t t = 0; t < num_samples + discard; ++t) { // Generate a new proposal according to some mutation strategy. // This is arbitrary and can be swapped. double x_dash = normal(generator) + x_t; - double acceptance_probability = std::min(pdf(x_dash)/pdf(x_t), 1.0); + double acceptance_probability = std::min(pdf(x_dash) / pdf(x_t), 1.0); double u = uniform(generator); // Accept "new state" according to the acceptance_probability - if(u <= acceptance_probability) { + if (u <= acceptance_probability) { x_t = x_dash; } - if(t >= discard) { + if (t >= discard) { samples.push_back(x_t); } } @@ -92,13 +106,17 @@ std::vector generate_samples(const double& start_point, const Function& * @param function The function to integrate * @param pdf The pdf to sample * @param num_samples The number of samples used to approximate the integral - * @returns The approximation of the integral according to 1/N \sum_{i}^N f(x_i) / p(x_i) + * @returns The approximation of the integral according to 1/N \sum_{i}^N f(x_i) + * / p(x_i) */ -double integral_monte_carlo(const double& start_point, const Function& function, const Function& pdf, const uint32_t& num_samples = 1000000) { +double integral_monte_carlo(const double& start_point, const Function& function, + const Function& pdf, + const uint32_t& num_samples = 1000000) { double integral = 0.0; - std::vector samples = generate_samples(start_point, pdf, num_samples); + std::vector samples = + generate_samples(start_point, pdf, num_samples); - for(double sample : samples) { + for (double sample : samples) { integral += function(sample) / pdf(sample); } @@ -113,8 +131,13 @@ double integral_monte_carlo(const double& start_point, const Function& function, * @returns void */ static void test() { - std::cout << "Disclaimer: Because this is a randomized algorithm," << std::endl; - std::cout << "it may happen that singular samples deviate from the true result." << std::endl << std::endl;; + std::cout << "Disclaimer: Because this is a randomized algorithm," + << std::endl; + std::cout + << "it may happen that singular samples deviate from the true result." + << std::endl + << std::endl; + ; math::monte_carlo::Function f; math::monte_carlo::Function pdf; @@ -122,60 +145,58 @@ static void test() { double lower_bound = 0, upper_bound = 0; /* \int_{-2}^{2} -x^2 + 4 dx */ - f = [&](double& x) { - return -x*x + 4.0; - }; + f = [&](double& x) { return -x * x + 4.0; }; lower_bound = -2.0; upper_bound = 2.0; pdf = [&](double& x) { - if(x >= lower_bound && x <= -1.0) { + if (x >= lower_bound && x <= -1.0) { return 0.1; } - if(x <= upper_bound && x >= 1.0) { + if (x <= upper_bound && x >= 1.0) { return 0.1; } - if(x > -1.0 && x < 1.0) { + if (x > -1.0 && x < 1.0) { return 0.4; } return 0.0; }; - integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf); + integral = math::monte_carlo::integral_monte_carlo( + (upper_bound - lower_bound) / 2.0, f, pdf); - std::cout << "This number should be close to 10.666666: " << integral << std::endl; + std::cout << "This number should be close to 10.666666: " << integral + << std::endl; /* \int_{0}^{1} e^x dx */ - f = [&](double& x) { - return std::exp(x); - }; + f = [&](double& x) { return std::exp(x); }; lower_bound = 0.0; upper_bound = 1.0; pdf = [&](double& x) { - if(x >= lower_bound && x <= 0.2) { + if (x >= lower_bound && x <= 0.2) { return 0.1; } - if(x > 0.2 && x <= 0.4) { + if (x > 0.2 && x <= 0.4) { return 0.4; } - if(x > 0.4 && x < upper_bound) { + if (x > 0.4 && x < upper_bound) { return 1.5; } return 0.0; }; - integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf); + integral = math::monte_carlo::integral_monte_carlo( + (upper_bound - lower_bound) / 2.0, f, pdf); - std::cout << "This number should be close to 1.7182818: " << integral << std::endl; + std::cout << "This number should be close to 1.7182818: " << integral + << std::endl; /* \int_{-\infty}^{\infty} sinc(x) dx, sinc(x) = sin(pi * x) / (pi * x) This is a difficult integral because of its infinite domain. Therefore, it may deviate largely from the expected result. */ - f = [&](double& x) { - return std::sin(M_PI * x) / (M_PI * x); - }; + f = [&](double& x) { return std::sin(M_PI * x) / (M_PI * x); }; pdf = [&](double& x) { return 1.0 / std::sqrt(2.0 * M_PI) * std::exp(-x * x / 2.0); @@ -183,7 +204,8 @@ static void test() { integral = math::monte_carlo::integral_monte_carlo(0.0, f, pdf, 10000000); - std::cout << "This number should be close to 1.0: " << integral << std::endl; + std::cout << "This number should be close to 1.0: " << integral + << std::endl; } /** diff --git a/range_queries/segtree.cpp b/range_queries/segtree.cpp index bc03b5428..71e6890fb 100644 --- a/range_queries/segtree.cpp +++ b/range_queries/segtree.cpp @@ -144,7 +144,7 @@ void update(std::vector *segtree, std::vector *lazy, * @returns void */ static void test() { - int64_t max = static_cast(2 * pow(2, ceil(log2(7))) - 1); + auto max = static_cast(2 * pow(2, ceil(log2(7))) - 1); assert(max == 15); std::vector arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max); @@ -172,7 +172,7 @@ int main() { uint64_t n = 0; std::cin >> n; - uint64_t max = static_cast(2 * pow(2, ceil(log2(n))) - 1); + auto max = static_cast(2 * pow(2, ceil(log2(n))) - 1); std::vector arr(n), lazy(max), segtree(max); int choice = 0; diff --git a/sorting/selection_sort.cpp b/sorting/selection_sort.cpp deleted file mode 100644 index 3854f52e6..000000000 --- a/sorting/selection_sort.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Selection Sort - -#include -using namespace std; - -int main() { - int Array[6]; - cout << "\nEnter any 6 Numbers for Unsorted Array : "; - - // Input - for (int i = 0; i < 6; i++) { - cin >> Array[i]; - } - - // Selection Sorting - for (int i = 0; i < 6; i++) { - int min = i; - for (int j = i + 1; j < 6; j++) { - if (Array[j] < Array[min]) { - min = j; // Finding the smallest number in Array - } - } - int temp = Array[i]; - Array[i] = Array[min]; - Array[min] = temp; - } - - // Output - cout << "\nSorted Array : "; - for (int i = 0; i < 6; i++) { - cout << Array[i] << "\t"; - } -} diff --git a/sorting/selection_sort_iterative.cpp b/sorting/selection_sort_iterative.cpp new file mode 100644 index 000000000..a9adac089 --- /dev/null +++ b/sorting/selection_sort_iterative.cpp @@ -0,0 +1,126 @@ +/****************************************************************************** + * @file + * @brief Implementation of the [Selection + * sort](https://en.wikipedia.org/wiki/Selection_sort) implementation using + * swapping + * @details + * The selection sort algorithm divides the input vector into two parts: a + * sorted subvector of items which is built up from left to right at the front + * (left) of the vector, and a subvector of the remaining unsorted items that + * occupy the rest of the vector. Initially, the sorted subvector is empty, and + * the unsorted subvector is the entire input vector. The algorithm proceeds by + * finding the smallest (or largest, depending on the sorting order) element in + * the unsorted subvector, exchanging (swapping) it with the leftmost unsorted + * element (putting it in sorted order), and moving the subvector boundaries one + * element to the right. + * + * ### Implementation + * + * SelectionSort + * The algorithm divides the input vector into two parts: the subvector of items + * already sorted, which is built up from left to right. Initially, the sorted + * subvector is empty and the unsorted subvector is the entire input vector. The + * algorithm proceeds by finding the smallest element in the unsorted subvector, + * exchanging (swapping) it with the leftmost unsorted element (putting it in + * sorted order), and moving the subvector boundaries one element to the right. + * + * @author [Lajat Manekar](https://github.com/Lazeeez) + * @author Unknown author + *******************************************************************************/ +#include /// for std::is_sorted +#include /// for std::assert +#include /// for IO operations +#include /// for std::vector + +/****************************************************************************** + * @namespace sorting + * @brief Sorting algorithms + *******************************************************************************/ +namespace sorting { +/****************************************************************************** + * @brief The main function which implements Selection sort + * @param arr vector to be sorted + * @param len length of vector to be sorted + * @returns @param array resultant sorted vector + *******************************************************************************/ + +std::vector selectionSort(const std::vector &arr, + uint64_t len) { + std::vector array( + arr.begin(), + arr.end()); // declare a vector in which result will be stored + for (uint64_t it = 0; it < len; ++it) { + uint64_t min = it; // set min value + for (uint64_t it2 = it + 1; it2 < len; ++it2) { + if (array[it2] < array[min]) { // check which element is smaller + min = it2; // store index of smallest element to min + } + } + + if (min != it) { // swap if min does not match to i + uint64_t tmp = array[min]; + array[min] = array[it]; + array[it] = tmp; + } + } + + return array; // return sorted vector +} +} // namespace sorting + +/******************************************************************************* + * @brief Self-test implementations + * @returns void + *******************************************************************************/ +static void test() { + // testcase #1 + // [1, 0, 0, 1, 1, 0, 2, 1] returns [0, 0, 0, 1, 1, 1, 1, 2] + std::vector vector1 = {1, 0, 0, 1, 1, 0, 2, 1}; + uint64_t vector1size = vector1.size(); + std::cout << "1st test... "; + std::vector result_test1; + result_test1 = sorting::selectionSort(vector1, vector1size); + assert(std::is_sorted(result_test1.begin(), result_test1.end())); + std::cout << "Passed" << std::endl; + + // testcase #2 + // [19, 22, 540, 241, 156, 140, 12, 1] returns [1, 12, 19, 22, 140, 156, + // 241,540] + std::vector vector2 = {19, 22, 540, 241, 156, 140, 12, 1}; + uint64_t vector2size = vector2.size(); + std::cout << "2nd test... "; + std::vector result_test2; + result_test2 = sorting::selectionSort(vector2, vector2size); + assert(std::is_sorted(result_test2.begin(), result_test2.end())); + std::cout << "Passed" << std::endl; + + // testcase #3 + // [11, 20, 30, 41, 15, 60, 82, 15] returns [11, 15, 15, 20, 30, 41, 60, 82] + std::vector vector3 = {11, 20, 30, 41, 15, 60, 82, 15}; + uint64_t vector3size = vector3.size(); + std::cout << "3rd test... "; + std::vector result_test3; + result_test3 = sorting::selectionSort(vector3, vector3size); + assert(std::is_sorted(result_test3.begin(), result_test3.end())); + std::cout << "Passed" << std::endl; + + // testcase #4 + // [1, 9, 11, 546, 26, 65, 212, 14, -11] returns [-11, 1, 9, 11, 14, 26, 65, + // 212, 546] + std::vector vector4 = {1, 9, 11, 546, 26, 65, 212, 14}; + uint64_t vector4size = vector2.size(); + std::cout << "4th test... "; + std::vector result_test4; + result_test4 = sorting::selectionSort(vector4, vector4size); + assert(std::is_sorted(result_test4.begin(), result_test4.end())); + std::cout << "Passed" << std::endl; +} + +/******************************************************************************* + * @brief Main function + * @returns 0 on exit + *******************************************************************************/ +int main() { + test(); // run self-test implementations + return 0; +} From e5135d8bd812f4348c1deffda897e80a97111c35 Mon Sep 17 00:00:00 2001 From: Alvin Philips Date: Tue, 26 Oct 2021 09:38:12 +0530 Subject: [PATCH 3/6] fix: Array left rotation (#1792) * Create reverse_binary_tree.cpp * Added documentation Added Documentation for the level_order_traversal() function, and implemented a print() function to display the tree to STDOUT * Added documentation * Renamed tests to test * Fixed issue with incorrect using statement * updating DIRECTORY.md * clang-format and clang-tidy fixes for fb86292d * Added Test cases * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Changed int to int64_t * Updated documentation wording * Rewrote array_left_rotation * Modified doc, fixed bug in shifting logic Fixed a mistake that would cause the array to shift incorrectly * clang-format and clang-tidy fixes for bd135686 * Update operations_on_datastructures/array_left_rotation.cpp Co-authored-by: David Leal * changed int to size_t * clang-format and clang-tidy fixes for 00e7daaf * clang-format and clang-tidy fixes for ed2aa3a7 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> --- .../array_left_rotation.cpp | 199 +++++++++++++++--- 1 file changed, 171 insertions(+), 28 deletions(-) diff --git a/operations_on_datastructures/array_left_rotation.cpp b/operations_on_datastructures/array_left_rotation.cpp index 7b8f7f279..8e63dcbc1 100644 --- a/operations_on_datastructures/array_left_rotation.cpp +++ b/operations_on_datastructures/array_left_rotation.cpp @@ -1,31 +1,174 @@ -#include -using namespace std; +/** + * @file + * @brief Implementation for the [Array Left + * Rotation](https://www.javatpoint.com/program-to-left-rotate-the-elements-of-an-array) + * algorithm. + * @details Shifting an array to the left involves moving each element of the + * array so that it occupies a position of a certain shift value before its + * current one. This implementation uses a result vector and does not mutate the + * input. + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @brief Prints the values of a vector sequentially, ending with a newline + * character. + * @param array Reference to the array to be printed + * @returns void + */ +void print(const std::vector &array) { + for (int32_t i : array) { + std::cout << i << " "; /// Print each value in the array + } + std::cout << "\n"; /// Print newline +} + +/** + * @brief Shifts the given vector to the left by the shift amount and returns a + * new vector with the result. The original vector is not mutated. + * @details Shifts the values of the vector, by creating a new vector and adding + * values from the shift index to the end, then appending the rest of the + * elements from the start of the vector. + * @param array A reference to the input std::vector + * @param shift The amount to be shifted to the left + * @returns A std::vector with the shifted values + */ +std::vector shift_left(const std::vector &array, + size_t shift) { + if (array.size() <= shift) { + return {}; ///< We got an invalid shift, return empty array + } + std::vector res(array.size()); ///< Result array + for (size_t i = shift; i < array.size(); i++) { + res[i - shift] = array[i]; ///< Add values after the shift index + } + for (size_t i = 0; i < shift; i++) { + res[array.size() - shift + i] = + array[i]; ///< Add the values from the start + } + return res; +} + +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check Union of Two Arrays. + */ +namespace tests { +using operations_on_datastructures::print; +using operations_on_datastructures::shift_left; +/** + * @brief A Test to check an simple case + * @returns void + */ +void test1() { + std::cout << "TEST CASE 1\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {3, 4, 5, 1, 2}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_left(arr, 2); + std::vector expected = {3, 4, 5, 1, 2}; + assert(res == expected); + print(res); ///< Should print 3 4 5 1 2 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an empty vector + * @returns void + */ +void test2() { + std::cout << "TEST CASE 2\n"; + std::cout << "Initialized arr = {}\n"; + std::cout << "Expected result: {}\n"; + std::vector arr = {}; + std::vector res = shift_left(arr, 2); + std::vector expected = {}; + assert(res == expected); + print(res); ///< Should print empty newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an invalid shift value + * @returns void + */ +void test3() { + std::cout << "TEST CASE 3\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_left(arr, 7); ///< 7 > 5 + std::vector expected = {}; + assert(res == expected); + print(res); ///< Should print empty newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check a very large input + * @returns void + */ +void test4() { + std::cout << "TEST CASE 4\n"; + std::cout << "Initialized arr = {2, 4, ..., 420}\n"; + std::cout << "Expected result: {4, 6, ..., 420, 2}\n"; + std::vector arr; + for (int i = 1; i <= 210; i++) { + arr.push_back(i * 2); + } + print(arr); + std::vector res = shift_left(arr, 1); + std::vector expected; + for (int i = 1; i < 210; i++) { + expected.push_back(arr[i]); + } + expected.push_back(2); + assert(res == expected); + print(res); ///< Should print {4, 6, ..., 420, 2} + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check a shift of zero + * @returns void + */ +void test5() { + std::cout << "TEST CASE 5\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {1, 2, 3, 4, 5}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_left(arr, 0); + assert(res == arr); + print(res); ///< Should print 1 2 3 4 5 + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of shift_left() function + * @returns void + */ +static void test() { + tests::test1(); + tests::test2(); + tests::test3(); + tests::test4(); + tests::test5(); +} + +/** + * @brief main function + * @returns 0 on exit + */ int main() { - int n, k; - cout << "Enter size of array=\t"; - cin >> n; - cout << "Enter Number of indeces u want to rotate the array to left=\t"; - cin >> k; - int a[n]; - cout << "Enter elements of array=\t"; - for (int i = 0; i < n; i++) { - cin >> a[i]; - } - int temp = 0; - for (int i = 0; i < k; i++) { - temp = a[0]; - for (int j = 0; j < n; j++) { - if (j == n - 1) { - a[n - 1] = temp; - } else { - a[j] = a[j + 1]; - } - } - } - cout << "Your rotated array is=\t"; - for (int j = 0; j < n; j++) { - cout << a[j] << " "; - } - getchar(); + test(); // run self-test implementations return 0; } From 050c99eb0ab3d814cce75110170309bafb8e6687 Mon Sep 17 00:00:00 2001 From: Focus <65309793+Focusucof@users.noreply.github.com> Date: Tue, 26 Oct 2021 03:49:58 -0400 Subject: [PATCH 4/6] feat: added math/volume.cpp (#1796) * feat: added math/volume.cpp * updating DIRECTORY.md * fix: style guide * fix: pi define to constexpr * fix: changed PI definition to function param * fix: style guide Co-authored-by: David Leal * fix: style guide Co-authored-by: David Leal * fix: added functions to math namespace * [fix/docs]: initialized test variables and added docs Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Ayaan Khan --- DIRECTORY.md | 1 + math/volume.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 math/volume.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 0c504e8c6..ae84537c9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -217,6 +217,7 @@ * [Sum Of Binomial Coefficient](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sum_of_binomial_coefficient.cpp) * [Sum Of Digits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/sum_of_digits.cpp) * [Vector Cross Product](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/vector_cross_product.cpp) + * [Volume](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/volume.cpp) ## Numerical Methods * [Bisection Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/bisection_method.cpp) diff --git a/math/volume.cpp b/math/volume.cpp new file mode 100644 index 000000000..87bfa6a82 --- /dev/null +++ b/math/volume.cpp @@ -0,0 +1,238 @@ +/** + * @file + * @brief Implmentations for the [volume](https://en.wikipedia.org/wiki/Volume) + * of various 3D shapes. + * @details The volume of a 3D shape is the amount of 3D space that the shape + * takes up. All shapes have a formula to get the volume of any given shape. + * These implementations support multiple return types. + * + * @author [Focusucof](https://github.com/Focusucof) + */ + +#include /// for assert +#include /// for std::pow +#include /// for std::uint32_t +#include /// for IO operations + +/** + * @namespace math + * @brief Mathematical algorithms + */ +namespace math { +/** + * @brief The volume of a [cube](https://en.wikipedia.org/wiki/Cube) + * @param length The length of the cube + * @returns The volume of the cube + */ +template +T cube_volume(T length) { + return std::pow(length, 3); +} + +/** + * @brief The volume of a + * [rectangular](https://en.wikipedia.org/wiki/Cuboid) prism + * @param length The length of the base rectangle + * @param width The width of the base rectangle + * @param height The height of the rectangular prism + * @returns The volume of the rectangular prism + */ +template +T rect_prism_volume(T length, T width, T height) { + return length * width * height; +} + +/** + * @brief The volume of a [cone](https://en.wikipedia.org/wiki/Cone) + * @param radius The radius of the base circle + * @param height The height of the cone + * @param PI The definition of the constant PI + * @returns The volume of the cone + */ +template +T cone_volume(T radius, T height, double PI = 3.14) { + return std::pow(radius, 2) * PI * height / 3; +} + +/** + * @brief The volume of a + * [triangular](https://en.wikipedia.org/wiki/Triangular_prism) prism + * @param base The length of the base triangle + * @param height The height of the base triangles + * @param depth The depth of the triangular prism (the height of the whole + * prism) + * @returns The volume of the triangular prism + */ +template +T triangle_prism_volume(T base, T height, T depth) { + return base * height * depth / 2; +} + +/** + * @brief The volume of a + * [pyramid](https://en.wikipedia.org/wiki/Pyramid_(geometry)) + * @param length The length of the base shape (or base for triangles) + * @param width The width of the base shape (or height for triangles) + * @param height The height of the pyramid + * @returns The volume of the pyramid + */ +template +T pyramid_volume(T length, T width, T height) { + return length * width * height / 3; +} + +/** + * @brief The volume of a [sphere](https://en.wikipedia.org/wiki/Sphere) + * @param radius The radius of the sphere + * @param PI The definition of the constant PI + * @returns The volume of the sphere + */ +template +T sphere_volume(T radius, double PI = 3.14) { + return PI * std::pow(radius, 3) * 4 / 3; +} + +/** + * @brief The volume of a [cylinder](https://en.wikipedia.org/wiki/Cylinder) + * @param radius The radius of the base circle + * @param height The height of the cylinder + * @param PI The definition of the constant PI + * @returns The volume of the cylinder + */ +template +T cylinder_volume(T radius, T height, double PI = 3.14) { + return PI * std::pow(radius, 2) * height; +} +} // namespace math + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // Input variables + uint32_t int_length = 0; // 32 bit integer length input + uint32_t int_width = 0; // 32 bit integer width input + uint32_t int_base = 0; // 32 bit integer base input + uint32_t int_height = 0; // 32 bit integer height input + uint32_t int_depth = 0; // 32 bit integer depth input + + double double_radius = NAN; // double radius input + double double_height = NAN; // double height input + + // Output variables + uint32_t int_expected = 0; // 32 bit integer expected output + uint32_t int_volume = 0; // 32 bit integer output + + double double_expected = NAN; // double expected output + double double_volume = NAN; // double output + + // 1st test + int_length = 5; + int_expected = 125; + int_volume = math::cube_volume(int_length); + + std::cout << "VOLUME OF A CUBE" << std::endl; + std::cout << "Input Length: " << int_length << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_volume << std::endl; + assert(int_volume == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 2nd test + int_length = 4; + int_width = 3; + int_height = 5; + int_expected = 60; + int_volume = math::rect_prism_volume(int_length, int_width, int_height); + + std::cout << "VOLUME OF A RECTANGULAR PRISM" << std::endl; + std::cout << "Input Length: " << int_length << std::endl; + std::cout << "Input Width: " << int_width << std::endl; + std::cout << "Input Height: " << int_height << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_volume << std::endl; + assert(int_volume == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 3rd test + double_radius = 5; + double_height = 7; + double_expected = 183.16666666666666; // truncated to 14 decimal places + double_volume = math::cone_volume(double_radius, double_height); + + std::cout << "VOLUME OF A CONE" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Input Height: " << double_height << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_volume << std::endl; + assert(double_volume == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 4th test + int_base = 3; + int_height = 4; + int_depth = 5; + int_expected = 30; + int_volume = math::triangle_prism_volume(int_base, int_height, int_depth); + + std::cout << "VOLUME OF A TRIANGULAR PRISM" << std::endl; + std::cout << "Input Base: " << int_base << std::endl; + std::cout << "Input Height: " << int_height << std::endl; + std::cout << "Input Depth: " << int_depth << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_volume << std::endl; + assert(int_volume == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 5th test + int_length = 10; + int_width = 3; + int_height = 5; + int_expected = 50; + int_volume = math::pyramid_volume(int_length, int_width, int_height); + + std::cout << "VOLUME OF A PYRAMID" << std::endl; + std::cout << "Input Length: " << int_length << std::endl; + std::cout << "Input Width: " << int_width << std::endl; + std::cout << "Input Height: " << int_height << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_volume << std::endl; + assert(int_volume == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 6th test + double_radius = 3; + double_expected = 113.04; + double_volume = math::sphere_volume(double_radius); + + std::cout << "VOLUME OF A SPHERE" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_volume << std::endl; + assert(double_volume == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 7th test + double_radius = 5; + double_height = 2; + double_expected = 157; + double_volume = math::cylinder_volume(double_radius, double_height); + + std::cout << "VOLUME OF A CYLINDER" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Input Height: " << double_height << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_volume << std::endl; + assert(double_volume == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From a9312b3901fd3237dc2d0dfe6230f026f04b9dc2 Mon Sep 17 00:00:00 2001 From: Tushar Mohan Date: Thu, 28 Oct 2021 07:18:58 +0530 Subject: [PATCH 5/6] feat: a different implementation of checking bipartite-ness of a graph (#1769) * feat: a different implementation of checking bipartite-ness of a graph * updating DIRECTORY.md * fix: code formatter error * fix: requested changes * fix: request changes * fix : requested changed * pass parameters by reference * pass parameters by reference * fix : visited to pointer * fix : line length below 80 chars Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Ayaan Khan --- DIRECTORY.md | 1 + graph/is_graph_bipartite2.cpp | 134 ++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 graph/is_graph_bipartite2.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index ae84537c9..618142c55 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -124,6 +124,7 @@ * [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hamiltons_cycle.cpp) * [Hopcroft Karp](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/hopcroft_karp.cpp) * [Is Graph Bipartite](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/is_graph_bipartite.cpp) + * [Is Graph Bipartite2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/is_graph_bipartite2.cpp) * [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kosaraju.cpp) * [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/kruskal.cpp) * [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/lowest_common_ancestor.cpp) diff --git a/graph/is_graph_bipartite2.cpp b/graph/is_graph_bipartite2.cpp new file mode 100644 index 000000000..07374da9a --- /dev/null +++ b/graph/is_graph_bipartite2.cpp @@ -0,0 +1,134 @@ +/** + * @brief Check whether a given graph is bipartite or not + * @details + * A bipartite graph is the one whose nodes can be divided into two + * disjoint sets in such a way that the nodes in a set are not + * connected to each other at all, i.e. no intra-set connections. + * The only connections that exist are that of inter-set, + * i.e. the nodes from one set are connected to a subset of nodes + * in the other set. + * In this implementation, using a graph in the form of adjacency + * list, check whether the given graph is a bipartite or not. + * + * References used: [GeeksForGeeks](https://www.geeksforgeeks.org/bipartite-graph/) + * @author [tushar2407](https://github.com/tushar2407) + */ +#include /// for IO operations +#include /// for queue data structure +#include /// for vector data structure +#include /// for assert + +/** + * @namespace graph + * @brief Graphical algorithms + */ +namespace graph { +/** + * @brief function to check whether the passed graph is bipartite or not + * @param graph is a 2D matrix whose rows or the first index signify the node + * and values in that row signify the nodes it is connected to + * @param index is the valus of the node currently under observation + * @param visited is the vector which stores whether a given node has been + * traversed or not yet + * @returns boolean + */ +bool checkBipartite( + const std::vector> &graph, + int64_t index, + std::vector *visited +) +{ + std::queue q; ///< stores the neighbouring node indexes in squence + /// of being reached + q.push(index); /// insert the current node into the queue + (*visited)[index] = 1; /// mark the current node as travelled + while(q.size()) + { + int64_t u = q.front(); + q.pop(); + for(uint64_t i=0;i> &graph) +{ + std::vector visited(graph.size()); ///< stores boolean values + /// which signify whether that node had been visited or not + + for(uint64_t i=0;i> graph = { + {1,3}, + {0,2}, + {1,3}, + {0,2} + }; + + assert(graph::isBipartite(graph) == true); /// check whether the above + /// defined graph is indeed bipartite + + std::vector> graph_not_bipartite = { + {1,2,3}, + {0,2}, + {0,1,3}, + {0,2} + }; + + assert(graph::isBipartite(graph_not_bipartite) == false); /// check whether + /// the above defined graph is indeed bipartite + std::cout << "All tests have successfully passed!\n"; +} +/** + * @brief Main function + * Instantitates a dummy graph of a small size with + * a few edges between random nodes. + * On applying the algorithm, it checks if the instantiated + * graph is bipartite or not. + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} From 4e3abd460102d74fe55f80882a71345ea34ee86a Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 29 Oct 2021 13:05:46 -0500 Subject: [PATCH 6/6] [feat/fix/docs]: Improvements in the `backtracking` folder (#1553) * [feat/fix/docs]: Improvements in the... ...`backtracking` folder, and minor fixes in the `others/iterative_tree_traversals.cpp` and the `math/check_prime.cpp` files. * clang-format and clang-tidy fixes for 9cc3951d Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> --- backtracking/graph_coloring.cpp | 40 ++- backtracking/knight_tour.cpp | 143 +++++----- backtracking/minimax.cpp | 36 +-- backtracking/n_queens.cpp | 157 ++++++----- .../n_queens_all_solution_optimised.cpp | 4 +- backtracking/nqueen_print_all_solutions.cpp | 25 +- backtracking/rat_maze.cpp | 24 +- backtracking/sudoku_solve.cpp | 260 ++++++++++-------- 8 files changed, 367 insertions(+), 322 deletions(-) diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp index baa10ab46..8fb328a1a 100644 --- a/backtracking/graph_coloring.cpp +++ b/backtracking/graph_coloring.cpp @@ -17,29 +17,38 @@ * @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include + +#include /// for std::array +#include /// for IO operations +#include /// for std::vector /** - * @namespace + * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { -/** A utility function to print solution +/** + * @namespace graph_coloring + * @brief Functions for the [Graph + * Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm, + */ +namespace graph_coloring { +/** + * @brief A utility function to print the 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; + std::cout << "Following are the assigned colors\n"; for (auto& col : color) { std::cout << col; } - std::cout << std::endl; + std::cout << "\n"; } -/** A utility function to check if the current color assignment is safe for +/** + * @brief 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 @@ -60,7 +69,8 @@ bool isSafe(int v, const std::array, V>& graph, return true; } -/** A recursive utility function to solve m coloring problem +/** + * @brief 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 @@ -74,28 +84,30 @@ void graphColoring(const std::array, V>& graph, int m, // base case: // If all vertices are assigned a color then return true if (v == V) { - backtracking::printSolution(color); + 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)) { + if (isSafe(v, graph, color, c)) { color[v] = c; // recur to assign colors to rest of the vertices - backtracking::graphColoring(graph, m, color, v + 1); + graphColoring(graph, m, color, v + 1); // If assigning color c doesn't lead to a solution then remove it color[v] = 0; } } } +} // namespace graph_coloring } // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { // Create following graph and test whether it is 3 colorable @@ -113,6 +125,6 @@ int main() { int m = 3; // Number of colors std::array color{}; - backtracking::graphColoring(graph, m, color, 0); + backtracking::graph_coloring::graphColoring(graph, m, color, 0); return 0; } diff --git a/backtracking/knight_tour.cpp b/backtracking/knight_tour.cpp index 88883ee07..0223462db 100644 --- a/backtracking/knight_tour.cpp +++ b/backtracking/knight_tour.cpp @@ -1,6 +1,7 @@ /** * @file - * @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm + * @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour) + * algorithm * * @details * A knight's tour is a sequence of moves of a knight on a chessboard @@ -12,92 +13,102 @@ * @author [Nikhil Arora](https://github.com/nikhilarora068) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include +#include /// for std::array +#include /// for IO operations /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * A utility function to check if i,j are valid indexes for N*N chessboard - * @tparam V number of vertices in array - * @param x current index in rows - * @param y current index in columns - * @param sol matrix where numbers are saved - * @returns `true` if .... - * @returns `false` if .... - */ - template - bool issafe(int x, int y, const std::array , V>& sol) { - return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1); - } - - /** - * Knight's tour algorithm - * @tparam V number of vertices in array - * @param x current index in rows - * @param y current index in columns - * @param mov movement to be done - * @param sol matrix where numbers are saved - * @param xmov next move of knight (x coordinate) - * @param ymov next move of knight (y coordinate) - * @returns `true` if solution exists - * @returns `false` if solution does not exist - */ - template - bool solve(int x, int y, int mov, std::array , V> &sol, - const std::array &xmov, std::array &ymov) { - int k, xnext, ynext; - - if (mov == V * V) { - return true; - } - - for (k = 0; k < V; k++) { - xnext = x + xmov[k]; - ynext = y + ymov[k]; - - if (backtracking::issafe(xnext, ynext, sol)) { - sol[xnext][ynext] = mov; - - if (backtracking::solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) { - return true; - } - else { - sol[xnext][ynext] = -1; - } - } - } - return false; - } -} // namespace backtracking +/** + * @namespace knight_tour + * @brief Functions for the [Knight's + * tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm + */ +namespace knight_tour { +/** + * A utility function to check if i,j are valid indexes for N*N chessboard + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param sol matrix where numbers are saved + * @returns `true` if .... + * @returns `false` if .... + */ +template +bool issafe(int x, int y, const std::array, V> &sol) { + return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1); +} /** - * Main function + * Knight's tour algorithm + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param mov movement to be done + * @param sol matrix where numbers are saved + * @param xmov next move of knight (x coordinate) + * @param ymov next move of knight (y coordinate) + * @returns `true` if solution exists + * @returns `false` if solution does not exist + */ +template +bool solve(int x, int y, int mov, std::array, V> &sol, + const std::array &xmov, std::array &ymov) { + int k = 0, xnext = 0, ynext = 0; + + if (mov == V * V) { + return true; + } + + for (k = 0; k < V; k++) { + xnext = x + xmov[k]; + ynext = y + ymov[k]; + + if (issafe(xnext, ynext, sol)) { + sol[xnext][ynext] = mov; + + if (solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) { + return true; + } else { + sol[xnext][ynext] = -1; + } + } + } + return false; +} +} // namespace knight_tour +} // namespace backtracking + +/** + * @brief Main function + * @returns 0 on exit */ int main() { const int n = 8; - std::array , n> sol = { 0 }; + std::array, n> sol = {0}; - int i, j; + int i = 0, j = 0; for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { sol[i][j] = -1; } + for (j = 0; j < n; j++) { + sol[i][j] = -1; + } } - std::array xmov = { 2, 1, -1, -2, -2, -1, 1, 2 }; - std::array ymov = { 1, 2, 2, 1, -1, -2, -2, -1 }; + std::array xmov = {2, 1, -1, -2, -2, -1, 1, 2}; + std::array ymov = {1, 2, 2, 1, -1, -2, -2, -1}; sol[0][0] = 0; - bool flag = backtracking::solve(0, 0, 1, sol, xmov, ymov); + bool flag = backtracking::knight_tour::solve(0, 0, 1, sol, xmov, ymov); if (flag == false) { std::cout << "Error: Solution does not exist\n"; - } - else { + } else { for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { std::cout << sol[i][j] << " "; } + for (j = 0; j < n; j++) { + std::cout << sol[i][j] << " "; + } std::cout << "\n"; } } diff --git a/backtracking/minimax.cpp b/backtracking/minimax.cpp index c39018805..b27c85e10 100644 --- a/backtracking/minimax.cpp +++ b/backtracking/minimax.cpp @@ -6,33 +6,34 @@ * @details * Minimax (sometimes MinMax, MM or saddle point) is a decision rule used in * artificial intelligence, decision theory, game theory, statistics, - * and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario. - * When dealing with gains, it is referred to as "maximin"—to maximize the minimum gain. - * Originally formulated for two-player zero-sum game theory, covering both the cases where players take - * alternate moves and those where they make simultaneous moves, it has also been extended to more - * complex games and to general decision-making in the presence of uncertainty. - * + * and philosophy for minimizing the possible loss for a worst case (maximum + * loss) scenario. When dealing with gains, it is referred to as "maximin"—to + * maximize the minimum gain. Originally formulated for two-player zero-sum game + * theory, covering both the cases where players take alternate moves and those + * where they make simultaneous moves, it has also been extended to more complex + * games and to general decision-making in the presence of uncertainty. + * * @author [Gleison Batista](https://github.com/gleisonbs) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include -#include +#include /// for std::max, std::min +#include /// for std::array +#include /// for log2 +#include /// for IO operations -/** +/** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { /** - * Check which number is the maximum/minimum in the array + * @brief Check which is the maximum/minimum number in the array * @param depth current depth in game tree * @param node_index current index in array * @param is_max if current index is the longest number * @param scores saved numbers in array * @param height maximum height for game tree - * @return maximum or minimum number + * @returns the maximum or minimum number */ template int minimax(int depth, int node_index, bool is_max, @@ -46,16 +47,17 @@ int minimax(int depth, int node_index, bool is_max, return is_max ? std::max(v1, v2) : std::min(v1, v2); } -} // namespace backtracking +} // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { std::array scores = {90, 23, 6, 33, 21, 65, 123, 34423}; double height = log2(scores.size()); - std::cout << "Optimal value: " << backtracking::minimax(0, 0, true, scores, height) - << std::endl; + std::cout << "Optimal value: " + << backtracking::minimax(0, 0, true, scores, height) << std::endl; return 0; } diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp index 89d907750..f9742eb7a 100644 --- a/backtracking/n_queens.cpp +++ b/backtracking/n_queens.cpp @@ -15,115 +15,114 @@ * @author [David Leal](https://github.com/Panquesito7) * */ -#include #include +#include /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * @namespace n_queens - * @brief Functions for [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle. - */ - namespace n_queens { - /** - * Utility function to print matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - */ - template - void printSolution(const std::array, n> &board) { - std::cout << "\n"; - for (int i = 0; i < n; i++) { +/** + * @namespace n_queens + * @brief Functions for [Eight + * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle. + */ +namespace n_queens { +/** + * Utility function to print matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + */ +template +void printSolution(const std::array, n> &board) { + std::cout << "\n"; + for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - std::cout << "" << board[i][j] << " "; + std::cout << "" << board[i][j] << " "; } std::cout << "\n"; - } } +} - /** - * Check if a queen can be placed on matrix - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param row current index in rows - * @param col current index in columns - * @returns `true` if queen can be placed on matrix - * @returns `false` if queen can't be placed on matrix - */ - template - bool isSafe(const std::array, n> &board, const int &row, - const int &col) { - int i = 0, j = 0; +/** + * Check if a queen can be placed on matrix + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param row current index in rows + * @param col current index in columns + * @returns `true` if queen can be placed on matrix + * @returns `false` if queen can't be placed on matrix + */ +template +bool isSafe(const std::array, n> &board, const int &row, + const int &col) { + int i = 0, j = 0; - // Check this row on left side - for (i = 0; i < col; i++) { + // Check this row on left side + for (i = 0; i < col; i++) { if (board[row][i]) { - return false; + return false; } - } - - // Check upper diagonal on left side - for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { - if (board[i][j]) { - return false; - } - } - // Check lower diagonal on left side - for (i = row, j = col; j >= 0 && i < n; i++, j--) { - if (board[i][j]) { - return false; - } - } - return true; } - /** - * Solve n queens problem - * @tparam n number of matrix size - * @param board matrix where numbers are saved - * @param col current index in columns - */ - template - void solveNQ(std::array, n> board, const int &col) { - if (col >= n) { + // Check upper diagonal on left side + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { + if (board[i][j]) { + return false; + } + } + // Check lower diagonal on left side + for (i = row, j = col; j >= 0 && i < n; i++, j--) { + if (board[i][j]) { + return false; + } + } + return true; +} + +/** + * Solve n queens problem + * @tparam n number of matrix size + * @param board matrix where numbers are saved + * @param col current index in columns + */ +template +void solveNQ(std::array, n> board, const int &col) { + if (col >= n) { printSolution(board); return; - } + } - // Consider this column and try placing - // this queen in all rows one by one - for (int i = 0; i < n; i++) { + // Consider this column and try placing + // this queen in all rows one by one + for (int i = 0; i < n; i++) { // Check if queen can be placed // on board[i][col] if (isSafe(board, i, col)) { - // Place this queen in matrix - board[i][col] = 1; + // Place this queen in matrix + board[i][col] = 1; - // Recursive to place rest of the queens - solveNQ(board, col + 1); + // Recursive to place rest of the queens + solveNQ(board, col + 1); - board[i][col] = 0; // backtrack + board[i][col] = 0; // backtrack } - } } - } // namespace n_queens -} // namespace backtracking +} +} // namespace n_queens +} // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { - const int n = 4; - std::array, n> board = { - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}), - std::array({0, 0, 0, 0}) - }; + const int n = 4; + std::array, n> board = { + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0})}; - backtracking::n_queens::solveNQ(board, 0); - return 0; + backtracking::n_queens::solveNQ(board, 0); + return 0; } diff --git a/backtracking/n_queens_all_solution_optimised.cpp b/backtracking/n_queens_all_solution_optimised.cpp index bd150a98d..525d4c2db 100644 --- a/backtracking/n_queens_all_solution_optimised.cpp +++ b/backtracking/n_queens_all_solution_optimised.cpp @@ -111,7 +111,7 @@ int main() { std::array, n> board{}; if (n % 2 == 0) { - for (int i = 0; i <= n / 2 - 1; i++) { // 😎 + for (int i = 0; i <= n / 2 - 1; i++) { if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) { board[i][0] = 1; backtracking::n_queens_optimized::NQueenSol(board, 1); @@ -119,7 +119,7 @@ int main() { } } } else { - for (int i = 0; i <= n / 2; i++) { // 😏 + for (int i = 0; i <= n / 2; i++) { if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) { board[i][0] = 1; backtracking::n_queens_optimized::NQueenSol(board, 1); diff --git a/backtracking/nqueen_print_all_solutions.cpp b/backtracking/nqueen_print_all_solutions.cpp index 5aa5c71a2..8824cf0a8 100644 --- a/backtracking/nqueen_print_all_solutions.cpp +++ b/backtracking/nqueen_print_all_solutions.cpp @@ -1,14 +1,14 @@ /** * @file - * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) + * @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) * puzzle, printing all solutions * * @author [Himani Negi](https://github.com/Himani2000) * @author [David Leal](https://github.com/Panquesito7) * */ -#include -#include +#include /// for std::array +#include /// for IO operations /** * @namespace backtracking @@ -17,12 +17,13 @@ namespace backtracking { /** * @namespace n_queens_all_solutions - * @brief Functions for [Eight - * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle with all solutions. + * @brief Functions for the [Eight + * Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle with all + * solutions. */ namespace n_queens_all_solutions { /** - * Utility function to print matrix + * @brief Utility function to print matrix * @tparam n number of matrix size * @param board matrix where numbers are saved */ @@ -38,7 +39,7 @@ void PrintSol(const std::array, n>& board) { } /** - * Check if a queen can be placed on matrix + * @brief Check if a queen can be placed on the matrix * @tparam n number of matrix size * @param board matrix where numbers are saved * @param row current index in rows @@ -47,7 +48,8 @@ void PrintSol(const std::array, n>& board) { * @returns `false` if queen can't be placed on matrix */ template -bool CanIMove(const std::array, n>& board, int row, int col) { +bool CanIMove(const std::array, n>& board, int row, + int col) { /// check in the row for (int i = 0; i < col; i++) { if (board[row][i] == 1) { @@ -70,7 +72,7 @@ bool CanIMove(const std::array, n>& board, int row, int col) } /** - * Solve n queens problem + * @brief Main function to solve the N Queens problem * @tparam n number of matrix size * @param board matrix where numbers are saved * @param col current index in columns @@ -89,11 +91,12 @@ void NQueenSol(std::array, n> board, int col) { } } } -} // namespace n_queens_all_solutions +} // namespace n_queens_all_solutions } // namespace backtracking /** - * Main function + * @brief Main function + * @returns 0 on exit */ int main() { const int n = 4; diff --git a/backtracking/rat_maze.cpp b/backtracking/rat_maze.cpp index 6dfda965c..60bc521c8 100644 --- a/backtracking/rat_maze.cpp +++ b/backtracking/rat_maze.cpp @@ -16,9 +16,9 @@ * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include -#include +#include /// for std::array +#include /// for assert +#include /// for IO operations /** * @namespace backtracking @@ -39,12 +39,14 @@ namespace rat_maze { * @param currposcol current position in columns * @param maze matrix where numbers are saved * @param soln matrix to problem solution - * @returns 0 on end + * @returns `true` if there exists a solution to move one step ahead in a column + * or in a row + * @returns `false` for the backtracking part */ template bool solveMaze(int currposrow, int currposcol, - const std::array, size> &maze, - std::array, size> soln) { + const std::array, size> &maze, + std::array, size> soln) { if ((currposrow == size - 1) && (currposcol == size - 1)) { soln[currposrow][currposcol] = 1; for (int i = 0; i < size; ++i) { @@ -78,10 +80,10 @@ bool solveMaze(int currposrow, int currposcol, } // namespace backtracking /** - * @brief Test implementations + * @brief Self-test implementations * @returns void */ -static void test(){ +static void test() { const int size = 4; std::array, size> maze = { std::array{1, 0, 1, 0}, std::array{1, 0, 1, 1}, @@ -96,8 +98,8 @@ static void test(){ } } - int currposrow = 0; // Current position in rows - int currposcol = 0; // Current position in columns + int currposrow = 0; // Current position in the rows + int currposcol = 0; // Current position in the columns assert(backtracking::rat_maze::solveMaze(currposrow, currposcol, maze, soln) == 1); @@ -108,6 +110,6 @@ static void test(){ * @returns 0 on exit */ int main() { - test(); // run the tests + test(); // run self-test implementations return 0; } diff --git a/backtracking/sudoku_solve.cpp b/backtracking/sudoku_solve.cpp index d631d5dfd..38ccfa0b4 100644 --- a/backtracking/sudoku_solve.cpp +++ b/backtracking/sudoku_solve.cpp @@ -3,155 +3,171 @@ * @brief [Sudoku Solver](https://en.wikipedia.org/wiki/Sudoku) algorithm. * * @details - * Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, originally called - * Number Place) is a logic-based, combinatorial number-placement puzzle. - * In classic sudoku, the objective is to fill a 9×9 grid with digits so that each column, - * each row, and each of the nine 3×3 subgrids that compose the grid (also called "boxes", "blocks", or "regions") + * Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, + * originally called Number Place) is a logic-based, combinatorial + * number-placement puzzle. In classic sudoku, the objective is to fill a 9×9 + * grid with digits so that each column, each row, and each of the nine 3×3 + * subgrids that compose the grid (also called "boxes", "blocks", or "regions") * contain all of the digits from 1 to 9. The puzzle setter provides a - * partially completed grid, which for a well-posed puzzle has a single solution. + * partially completed grid, which for a well-posed puzzle has a single + * solution. * * @author [DarthCoder3200](https://github.com/DarthCoder3200) * @author [David Leal](https://github.com/Panquesito7) */ -#include -#include +#include /// for assert +#include /// for IO operations /** * @namespace backtracking * @brief Backtracking algorithms */ namespace backtracking { - /** - * Checks if it's possible to place a number 'no' - * @tparam V number of vertices in the array - * @param mat matrix where numbers are saved - * @param i current index in rows - * @param j current index in columns - * @param no number to be added in matrix - * @param n number of times loop will run - * @returns `true` if 'mat' is different from 'no' - * @returns `false` if 'mat' equals to 'no' - */ - template - bool isPossible(const std::array , V> &mat, int i, int j, int no, int n) { - /// 'no' shouldn't be present in either row i or column j - for (int x = 0; x < n; x++) { - if (mat[x][j] == no || mat[i][x] == no) { +/** + * @namespace sudoku_solver + * @brief Functions for the [Sudoku + * Solver](https://en.wikipedia.org/wiki/Sudoku) implementation + */ +namespace sudoku_solver { +/** + * @brief Check if it's possible to place a number (`no` parameter) + * @tparam V number of vertices in the array + * @param mat matrix where numbers are saved + * @param i current index in rows + * @param j current index in columns + * @param no number to be added in matrix + * @param n number of times loop will run + * @returns `true` if 'mat' is different from 'no' + * @returns `false` if 'mat' equals to 'no' + */ +template +bool isPossible(const std::array, V> &mat, int i, int j, + int no, int n) { + /// `no` shouldn't be present in either row i or column j + for (int x = 0; x < n; x++) { + if (mat[x][j] == no || mat[i][x] == no) { + return false; + } + } + + /// `no` shouldn't be present in the 3*3 subgrid + int sx = (i / 3) * 3; + int sy = (j / 3) * 3; + + for (int x = sx; x < sx + 3; x++) { + for (int y = sy; y < sy + 3; y++) { + if (mat[x][y] == no) { return false; } } + } - /// 'no' shouldn't be present in the 3*3 subgrid - int sx = (i / 3) * 3; - int sy = (j / 3) * 3; - - for (int x = sx; x < sx + 3; x++) { - for (int y = sy; y < sy + 3; y++) { - if (mat[x][y] == no) { - return false; - } + return true; +} +/** + * @brief Utility function to print the matrix + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param starting_mat copy of mat, required by printMat for highlighting the + * differences + * @param n number of times loop will run + * @return void + */ +template +void printMat(const std::array, V> &mat, + const std::array, V> &starting_mat, int n) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (starting_mat[i][j] != mat[i][j]) { + std::cout << "\033[93m" << mat[i][j] << "\033[0m" + << " "; + } else { + std::cout << mat[i][j] << " "; + } + if ((j + 1) % 3 == 0) { + std::cout << '\t'; } } - - return true; - } - /** - * Utility function to print matrix - * @tparam V number of vertices in array - * @param mat matrix where numbers are saved - * @param starting_mat copy of mat, required by printMat for highlighting the differences - * @param n number of times loop will run - * @return void - */ - template - void printMat(const std::array , V> &mat, const std::array , V> &starting_mat, int n) { - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - if (starting_mat[i][j] != mat[i][j]) { - std::cout << "\033[93m" << mat[i][j] << "\033[0m" << " "; - } else { - std::cout << mat[i][j] << " "; - } - if ((j + 1) % 3 == 0) { - std::cout << '\t'; - } - } - if ((i + 1) % 3 == 0) { - std::cout << std::endl; - } + if ((i + 1) % 3 == 0) { std::cout << std::endl; } + std::cout << std::endl; } - - /** - * Sudoku algorithm - * @tparam V number of vertices in array - * @param mat matrix where numbers are saved - * @param starting_mat copy of mat, required by printMat for highlighting the differences - * @param i current index in rows - * @param j current index in columns - * @returns `true` if 'no' was placed - * @returns `false` if 'no' was not placed - */ - template - bool solveSudoku(std::array , V> &mat, const std::array , V> &starting_mat, int i, int j) { - /// Base Case - if (i == 9) { - /// Solved for 9 rows already - backtracking::printMat(mat, starting_mat, 9); - return true; - } - - /// Crossed the last Cell in the row - if (j == 9) { - return backtracking::solveSudoku(mat, starting_mat, i + 1, 0); - } - - /// Blue Cell - Skip - if (mat[i][j] != 0) { - return backtracking::solveSudoku(mat, starting_mat, i, j + 1); - } - /// White Cell - /// Try to place every possible no - for (int no = 1; no <= 9; no++) { - if (backtracking::isPossible(mat, i, j, no, 9)) { - /// Place the 'no' - assuming a solution will exist - mat[i][j] = no; - bool solution_found = backtracking::solveSudoku(mat, starting_mat, i, j + 1); - if (solution_found) { - return true; - } - /// Couldn't find a solution - /// loop will place the next no. - } - } - /// Solution couldn't be found for any of the numbers provided - mat[i][j] = 0; - return false; - } -} // namespace backtracking +} /** - * Main function + * @brief Main function to implement the Sudoku algorithm + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param starting_mat copy of mat, required by printMat for highlighting the + * differences + * @param i current index in rows + * @param j current index in columns + * @returns `true` if 'no' was placed + * @returns `false` if 'no' was not placed + */ +template +bool solveSudoku(std::array, V> &mat, + const std::array, V> &starting_mat, int i, + int j) { + /// Base Case + if (i == 9) { + /// Solved for 9 rows already + printMat(mat, starting_mat, 9); + return true; + } + + /// Crossed the last Cell in the row + if (j == 9) { + return solveSudoku(mat, starting_mat, i + 1, 0); + } + + /// Blue Cell - Skip + if (mat[i][j] != 0) { + return solveSudoku(mat, starting_mat, i, j + 1); + } + /// White Cell + /// Try to place every possible no + for (int no = 1; no <= 9; no++) { + if (isPossible(mat, i, j, no, 9)) { + /// Place the 'no' - assuming a solution will exist + mat[i][j] = no; + bool solution_found = solveSudoku(mat, starting_mat, i, j + 1); + if (solution_found) { + return true; + } + /// Couldn't find a solution + /// loop will place the next `no`. + } + } + /// Solution couldn't be found for any of the numbers provided + mat[i][j] = 0; + return false; +} +} // namespace sudoku_solver +} // namespace backtracking + +/** + * @brief Main function + * @returns 0 on exit */ int main() { const int V = 9; - std::array , V> mat = { - std::array {5, 3, 0, 0, 7, 0, 0, 0, 0}, - std::array {6, 0, 0, 1, 9, 5, 0, 0, 0}, - std::array {0, 9, 8, 0, 0, 0, 0, 6, 0}, - std::array {8, 0, 0, 0, 6, 0, 0, 0, 3}, - std::array {4, 0, 0, 8, 0, 3, 0, 0, 1}, - std::array {7, 0, 0, 0, 2, 0, 0, 0, 6}, - std::array {0, 6, 0, 0, 0, 0, 2, 8, 0}, - std::array {0, 0, 0, 4, 1, 9, 0, 0, 5}, - std::array {0, 0, 0, 0, 8, 0, 0, 7, 9} - }; + std::array, V> mat = { + std::array{5, 3, 0, 0, 7, 0, 0, 0, 0}, + std::array{6, 0, 0, 1, 9, 5, 0, 0, 0}, + std::array{0, 9, 8, 0, 0, 0, 0, 6, 0}, + std::array{8, 0, 0, 0, 6, 0, 0, 0, 3}, + std::array{4, 0, 0, 8, 0, 3, 0, 0, 1}, + std::array{7, 0, 0, 0, 2, 0, 0, 0, 6}, + std::array{0, 6, 0, 0, 0, 0, 2, 8, 0}, + std::array{0, 0, 0, 4, 1, 9, 0, 0, 5}, + std::array{0, 0, 0, 0, 8, 0, 0, 7, 9}}; - backtracking::printMat(mat, mat, 9); + backtracking::sudoku_solver::printMat(mat, mat, 9); std::cout << "Solution " << std::endl; - std::array , V> starting_mat = mat; - backtracking::solveSudoku(mat, starting_mat, 0, 0); + std::array, V> starting_mat = mat; + backtracking::sudoku_solver::solveSudoku(mat, starting_mat, 0, 0); return 0; }