From 2e6b71e20620b4d2bde5009d2da8efe99eabc26c Mon Sep 17 00:00:00 2001 From: Urwashi Kumrawat <76898392+uru0120@users.noreply.github.com> Date: Tue, 12 Oct 2021 23:19:39 +0530 Subject: [PATCH 01/15] feat: Adding switch-case and removing if-else-if (#1727) * Adding switch-case and removing if-else-if * [feat/fix]: Update Co-authored-by: David Leal --- data_structures/stack_using_linked_list.cpp | 22 ++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index 3dcf03f8a..202c5c9b6 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -36,19 +36,23 @@ void show() { int main() { int ch, x; do { + std::cout << "\n0. Exit or Ctrl+C"; std::cout << "\n1. Push"; std::cout << "\n2. Pop"; std::cout << "\n3. Print"; - std::cout << "\nEnter Your Choice : "; + std::cout << "\nEnter Your Choice: "; std::cin >> ch; - if (ch == 1) { - std::cout << "\nInsert : "; - std::cin >> x; - push(x); - } else if (ch == 2) { - pop(); - } else if (ch == 3) { - show(); + switch(ch){ + case 0: break; + case 1: std::cout << "\nInsert : "; + std::cin >> x; + push(x); + break; + case 2: pop(); + break; + case 3: show(); + break; + default: std::cout << "Invalid option!\n"; break; } } while (ch != 0); From 89bfc1244e658ebe4e1b09ba6800815b4f103f36 Mon Sep 17 00:00:00 2001 From: Harsh Tripathi <63543719+happy-t@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:19:09 -0700 Subject: [PATCH 02/15] fix: Armstrong number bug fixes (#1689) * added a new directory named Recursion and a most common exxample of recusion i.e. Tower of Hanoi in it * Added Comments * Bug fixed according to the correct definition of armstrong_number * Bug Fixed in armstrong_number.cpp Bug Fixed in armstrong_number.cpp according to the correct definition of armstrong_number. * Update armstrong_number.cpp * Added documentation * Delete Recursion directory * Update armstrong_number.cpp * Update dynamic_programming/armstrong_number.cpp Co-authored-by: David Leal * Update armstrong_number.cpp fixed errors. * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Update armstrong_number.cpp Applied suggested changes. * Update armstrong_number.cpp Co-authored-by: David Leal --- dynamic_programming/armstrong_number.cpp | 44 +++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/dynamic_programming/armstrong_number.cpp b/dynamic_programming/armstrong_number.cpp index 270a705f7..ba8f054dd 100644 --- a/dynamic_programming/armstrong_number.cpp +++ b/dynamic_programming/armstrong_number.cpp @@ -1,21 +1,41 @@ // Program to check whether a number is an armstrong number or not #include - +#include using std::cin; using std::cout; int main() { - int n, k, d, s = 0; - cout << "Enter a number:"; + int n = 0, temp = 0, rem = 0, count = 0, sum = 0; + cout << "Enter a number: "; cin >> n; - k = n; - while (k != 0) { - d = k % 10; - s += d * d * d; - k /= 10; + + temp = n; + + /* First Count the number of digits + in the given number */ + while(temp != 0) { + temp /= 10; + count++; } - if (s == n) - cout << n << "is an armstrong number"; - else - cout << n << "is not an armstrong number"; + + /* Calaculation for checking of armstrongs number i.e. + in a n digit number sum of the digits raised to a power of n + is equal to the original number */ + + temp = n; + while(temp!=0) { + rem = temp%10; + sum += (int) pow(rem,count); + temp/=10; + } + + + if (sum == n) { + cout << n << " is an armstrong number"; + } + else { + cout << n << " is not an armstrong number"; + } + + return 0; } From 5a654fb85bcd064d1e4a9a32c6516fda4b1abac7 Mon Sep 17 00:00:00 2001 From: Domenic Zingsheim Date: Wed, 13 Oct 2021 21:22:32 +0000 Subject: [PATCH 03/15] feat: add geometric distribution (#1699) * feat: add geometric distribution * test: Add test for geometric dist * fix: Make range_tries inclusive * docs: Add documentation for geometric distribution * fix: clang warnings in geometric_dist * updating DIRECTORY.md * fix: Remove extra line Co-authored-by: David Leal * fix: Remove file name Co-authored-by: David Leal * fix: Add return value of void function Co-authored-by: David Leal * fix: Add comment for test function Co-authored-by: David Leal * fix: Update successful test message Co-authored-by: David Leal * fix: Add geometric_dist namespace Co-authored-by: David Leal * fix: Remove extra line Co-authored-by: David Leal * fix: Close comment * docs: Fix documentation Co-authored-by: David Leal * fix: Add const to parameter Co-authored-by: David Leal * fix: Make class methods const Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + probability/geometric_dist.cpp | 236 +++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 probability/geometric_dist.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 7d206c91c..6c6e7711e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -266,6 +266,7 @@ * [Addition Rule](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/addition_rule.cpp) * [Bayes Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/bayes_theorem.cpp) * [Binomial Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/binomial_dist.cpp) + * [Geometric Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/geometric_dist.cpp) * [Poisson Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/poisson_dist.cpp) * [Windowed Median](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/windowed_median.cpp) diff --git a/probability/geometric_dist.cpp b/probability/geometric_dist.cpp new file mode 100644 index 000000000..9be1d0e77 --- /dev/null +++ b/probability/geometric_dist.cpp @@ -0,0 +1,236 @@ +/** + * @file + * @brief [Geometric Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) + * + * @details + * The geometric distribution models the experiment of doing Bernoulli trials until a + * sucess was observed. There are two formulations of the geometric distribution: + * 1) The probability distribution of the number X of Bernoulli trials needed to get one success, supported on the set { 1, 2, 3, ... } + * 2) The probability distribution of the number Y = X − 1 of failures before the first success, supported on the set { 0, 1, 2, 3, ... } + * Here, the first one is implemented. + * + * Common variables used: + * p - The success probability + * k - The number of tries + * + * @author [Domenic Zingsheim](https://github.com/DerAndereDomenic) + */ + +#include /// for assert +#include /// for math functions +#include /// for fixed size data types +#include /// for time to initialize rng +#include /// for std::cout +#include /// for std::numeric_limits +#include /// for random numbers +#include /// for std::vector + +/** + * @namespace probability + * @brief Probability algorithms + */ +namespace probability { +/** + * @namespace geometric_dist + * @brief Functions for the [Geometric Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) algorithm implementation + */ +namespace geometric_dist { +/** + * @brief Returns a random number between [0,1] + * @returns A uniformly distributed random number between 0 (included) and 1 (included) + */ +float generate_uniform() { + return static_cast(rand()) / static_cast(RAND_MAX); +} + +/** + * @brief A class to model the geometric distribution + */ +class geometric_distribution +{ +private: + float p; ///< The succes probability p + +public: + /** + * @brief Constructor for the geometric distribution + * @param p The success probability + */ + explicit geometric_distribution(const float& p) : p(p) {} + + /** + * @brief The expected value of a geometrically distributed random variable X + * @returns E[X] = 1/p + */ + float expected_value() const { + return 1.0f/ p; + } + + /** + * @brief The variance of a geometrically distributed random variable X + * @returns V[X] = (1 - p) / p^2 + */ + float variance() const { + return (1.0f - p) / (p * p); + } + + /** + * @brief The standard deviation of a geometrically distributed random variable X + * @returns \sigma = \sqrt{V[X]} + */ + float standard_deviation() const { + return std::sqrt(variance()); + } + + /** + * @brief The probability density function + * @details As we use the first definition of the geometric series (1), + * we are doing k - 1 failed trials and the k-th trial is a success. + * @param k The number of trials to observe the first success in [1,\infty) + * @returns A number between [0,1] according to p * (1-p)^{k-1} + */ + float probability_density(const uint32_t& k) const { + return std::pow((1.0f - p), static_cast(k - 1)) * p; + } + + /** + * @brief The cumulative distribution function + * @details The sum of all probabilities up to (and including) k trials. Basically CDF(k) = P(x <= k) + * @param k The number of trials in [1,\infty) + * @returns The probability to have success within k trials + */ + float cumulative_distribution(const uint32_t& k) const { + return 1.0f - std::pow((1.0f - p), static_cast(k)); + } + + /** + * @brief The inverse cumulative distribution function + * @details This functions answers the question: Up to how many trials are needed to have success with a probability of cdf? + * The exact floating point value is reported. + * @param cdf The probability in [0,1] + * @returns The number of (exact) trials. + */ + float inverse_cumulative_distribution(const float& cdf) const { + return std::log(1.0f - cdf) / std::log(1.0f - p); + } + + /** + * @brief Generates a (discrete) sample according to the geometrical distribution + * @returns A geometrically distributed number in [1,\infty) + */ + uint32_t draw_sample() const { + float uniform_sample = generate_uniform(); + return static_cast(inverse_cumulative_distribution(uniform_sample)) + 1; + } + + /** + * @brief This function computes the probability to have success in a given range of tries + * @details Computes P(min_tries <= x <= max_tries). + * Can be used to calculate P(x >= min_tries) by not passing a second argument. + * Can be used to calculate P(x <= max_tries) by passing 1 as the first argument + * @param min_tries The minimum number of tries in [1,\infty) (inclusive) + * @param max_tries The maximum number of tries in [min_tries, \infty) (inclusive) + * @returns The probability of having success within a range of tries [min_tries, max_tries] + */ + float range_tries(const uint32_t& min_tries = 1, const uint32_t& max_tries = std::numeric_limits::max()) const { + float cdf_lower = cumulative_distribution(min_tries - 1); + float cdf_upper = max_tries == std::numeric_limits::max() ? 1.0f : cumulative_distribution(max_tries); + return cdf_upper - cdf_lower; + } +}; +} // namespace geometric_dist +} // namespace probability + +/** + * @brief Tests the sampling method of the geometric distribution + * @details Draws 1000000 random samples and estimates mean and variance + * These should be close to the expected value and variance of the given distribution to pass. + * @param dist The distribution to test + */ +void sample_test(const probability::geometric_dist::geometric_distribution& dist) { + uint32_t n_tries = 1000000; + std::vector tries; + tries.resize(n_tries); + + float mean = 0.0f; + for (uint32_t i = 0; i < n_tries; ++i) { + tries[i] = static_cast(dist.draw_sample()); + mean += tries[i]; + } + + mean /= static_cast(n_tries); + + float var = 0.0f; + for (uint32_t i = 0; i < n_tries; ++i) { + var += (tries[i] - mean) * (tries[i] - mean); + } + + //Unbiased estimate of variance + var /= static_cast(n_tries - 1); + + std::cout << "This value should be near " << dist.expected_value() << ": " << mean << std::endl; + std::cout << "This value should be near " << dist.variance() << ": " << var << std::endl; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + probability::geometric_dist::geometric_distribution dist(0.3); + + const float threshold = 1e-3f; + + std::cout << "Starting tests for p = 0.3..." << std::endl; + assert(std::abs(dist.expected_value() - 3.33333333f) < threshold); + assert(std::abs(dist.variance() - 7.77777777f) < threshold); + assert(std::abs(dist.standard_deviation() - 2.788866755) < threshold); + assert(std::abs(dist.probability_density(5) - 0.07203) < threshold); + assert(std::abs(dist.cumulative_distribution(6) - 0.882351) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.range_tries() - 1.0f) < threshold); + assert(std::abs(dist.range_tries(3) - 0.49f) < threshold); + assert(std::abs(dist.range_tries(5, 11) - 0.2203267f) < threshold); + std::cout << "All tests passed" << std::endl; + sample_test(dist); + + dist = probability::geometric_dist::geometric_distribution(0.5f); + + std::cout << "Starting tests for p = 0.5..." << std::endl; + assert(std::abs(dist.expected_value() - 2.0f) < threshold); + assert(std::abs(dist.variance() - 2.0f) < threshold); + assert(std::abs(dist.standard_deviation() - 1.4142135f) < threshold); + assert(std::abs(dist.probability_density(5) - 0.03125) < threshold); + assert(std::abs(dist.cumulative_distribution(6) - 0.984375) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.range_tries() - 1.0f) < threshold); + assert(std::abs(dist.range_tries(3) - 0.25f) < threshold); + assert(std::abs(dist.range_tries(5, 11) - 0.062011f) < threshold); + std::cout << "All tests passed" << std::endl; + sample_test(dist); + + dist = probability::geometric_dist::geometric_distribution(0.8f); + + std::cout << "Starting tests for p = 0.8..." << std::endl; + assert(std::abs(dist.expected_value() - 1.25f) < threshold); + assert(std::abs(dist.variance() - 0.3125f) < threshold); + assert(std::abs(dist.standard_deviation() - 0.559016f) < threshold); + assert(std::abs(dist.probability_density(5) - 0.00128) < threshold); + assert(std::abs(dist.cumulative_distribution(6) - 0.999936) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.range_tries() - 1.0f) < threshold); + assert(std::abs(dist.range_tries(3) - 0.04f) < threshold); + assert(std::abs(dist.range_tries(5, 11) - 0.00159997f) < threshold); + std::cout << "All tests have successfully passed!" << std::endl; + sample_test(dist); +} + +/** + * @brief Main function + * @return 0 on exit + */ +int main() { + srand(time(nullptr)); + test(); // run self-test implementations + return 0; +} From 85721be69b4011d4feda665c03147525bab67b7a Mon Sep 17 00:00:00 2001 From: Anuran Roy <76481787+anuran-roy@users.noreply.github.com> Date: Fri, 15 Oct 2021 00:04:55 +0530 Subject: [PATCH 04/15] feat: Modify search/text_search.cpp (#1662) * Modified search/text_search.cpp * Added tests * Added a few test cases * Added a few more test cases and documentation * Minor fix * Minor fixes * Minor fixes * Minor output fixes * Minor output fixes * Minor readability fixes * clang-format and clang-tidy fixes for a01765a6 * Restored original settings * clang-format and clang-tidy fixes for 6a8f3a4e Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- data_structures/stack_using_linked_list.cpp | 24 ++-- dynamic_programming/armstrong_number.cpp | 26 ++-- probability/geometric_dist.cpp | 128 ++++++++++++-------- probability/windowed_median.cpp | 90 ++++++++------ search/text_search.cpp | 72 +++++++++-- 5 files changed, 217 insertions(+), 123 deletions(-) diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp index 202c5c9b6..a87e6efb0 100644 --- a/data_structures/stack_using_linked_list.cpp +++ b/data_structures/stack_using_linked_list.cpp @@ -15,7 +15,7 @@ void push(int x) { } void pop() { - if (top_var == NULL) { + if (top_var == nullptr) { std::cout << "\nUnderflow"; } else { node *t = top_var; @@ -27,14 +27,14 @@ void pop() { void show() { node *t = top_var; - while (t != NULL) { + while (t != nullptr) { std::cout << t->val << "\n"; t = t->next; } } int main() { - int ch, x; + int ch = 0, x = 0; do { std::cout << "\n0. Exit or Ctrl+C"; std::cout << "\n1. Push"; @@ -42,17 +42,23 @@ int main() { std::cout << "\n3. Print"; std::cout << "\nEnter Your Choice: "; std::cin >> ch; - switch(ch){ - case 0: break; - case 1: std::cout << "\nInsert : "; + switch (ch) { + case 0: + break; + case 1: + std::cout << "\nInsert : "; std::cin >> x; push(x); break; - case 2: pop(); + case 2: + pop(); break; - case 3: show(); + case 3: + show(); + break; + default: + std::cout << "Invalid option!\n"; break; - default: std::cout << "Invalid option!\n"; break; } } while (ch != 0); diff --git a/dynamic_programming/armstrong_number.cpp b/dynamic_programming/armstrong_number.cpp index ba8f054dd..53f1be9fe 100644 --- a/dynamic_programming/armstrong_number.cpp +++ b/dynamic_programming/armstrong_number.cpp @@ -1,6 +1,6 @@ // Program to check whether a number is an armstrong number or not -#include #include +#include using std::cin; using std::cout; @@ -8,34 +8,32 @@ int main() { int n = 0, temp = 0, rem = 0, count = 0, sum = 0; cout << "Enter a number: "; cin >> n; - + temp = n; - + /* First Count the number of digits in the given number */ - while(temp != 0) { + while (temp != 0) { temp /= 10; count++; } - /* Calaculation for checking of armstrongs number i.e. + /* Calaculation for checking of armstrongs number i.e. in a n digit number sum of the digits raised to a power of n is equal to the original number */ - + temp = n; - while(temp!=0) { - rem = temp%10; - sum += (int) pow(rem,count); - temp/=10; + while (temp != 0) { + rem = temp % 10; + sum += static_cast(pow(rem, count)); + temp /= 10; } - if (sum == n) { cout << n << " is an armstrong number"; - } - else { + } else { cout << n << " is not an armstrong number"; } - + return 0; } diff --git a/probability/geometric_dist.cpp b/probability/geometric_dist.cpp index 9be1d0e77..a9bc7aeb6 100644 --- a/probability/geometric_dist.cpp +++ b/probability/geometric_dist.cpp @@ -1,13 +1,16 @@ /** * @file - * @brief [Geometric Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) + * @brief [Geometric + * Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) * * @details - * The geometric distribution models the experiment of doing Bernoulli trials until a - * sucess was observed. There are two formulations of the geometric distribution: - * 1) The probability distribution of the number X of Bernoulli trials needed to get one success, supported on the set { 1, 2, 3, ... } - * 2) The probability distribution of the number Y = X − 1 of failures before the first success, supported on the set { 0, 1, 2, 3, ... } - * Here, the first one is implemented. + * The geometric distribution models the experiment of doing Bernoulli trials + * until a sucess was observed. There are two formulations of the geometric + * distribution: 1) The probability distribution of the number X of Bernoulli + * trials needed to get one success, supported on the set { 1, 2, 3, ... } 2) + * The probability distribution of the number Y = X − 1 of failures before the + * first success, supported on the set { 0, 1, 2, 3, ... } Here, the first one + * is implemented. * * Common variables used: * p - The success probability @@ -16,14 +19,14 @@ * @author [Domenic Zingsheim](https://github.com/DerAndereDomenic) */ -#include /// for assert -#include /// for math functions -#include /// for fixed size data types -#include /// for time to initialize rng -#include /// for std::cout -#include /// for std::numeric_limits -#include /// for random numbers -#include /// for std::vector +#include /// for assert +#include /// for math functions +#include /// for fixed size data types +#include /// for time to initialize rng +#include /// for std::cout +#include /// for std::numeric_limits +#include /// for random numbers +#include /// for std::vector /** * @namespace probability @@ -32,12 +35,15 @@ namespace probability { /** * @namespace geometric_dist - * @brief Functions for the [Geometric Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) algorithm implementation + * @brief Functions for the [Geometric + * Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) algorithm + * implementation */ namespace geometric_dist { /** * @brief Returns a random number between [0,1] - * @returns A uniformly distributed random number between 0 (included) and 1 (included) + * @returns A uniformly distributed random number between 0 (included) and 1 + * (included) */ float generate_uniform() { return static_cast(rand()) / static_cast(RAND_MAX); @@ -46,12 +52,11 @@ float generate_uniform() { /** * @brief A class to model the geometric distribution */ -class geometric_distribution -{ -private: - float p; ///< The succes probability p +class geometric_distribution { + private: + float p; ///< The succes probability p -public: + public: /** * @brief Constructor for the geometric distribution * @param p The success probability @@ -59,28 +64,24 @@ public: explicit geometric_distribution(const float& p) : p(p) {} /** - * @brief The expected value of a geometrically distributed random variable X + * @brief The expected value of a geometrically distributed random variable + * X * @returns E[X] = 1/p */ - float expected_value() const { - return 1.0f/ p; - } + float expected_value() const { return 1.0f / p; } /** * @brief The variance of a geometrically distributed random variable X * @returns V[X] = (1 - p) / p^2 */ - float variance() const { - return (1.0f - p) / (p * p); - } + float variance() const { return (1.0f - p) / (p * p); } /** - * @brief The standard deviation of a geometrically distributed random variable X + * @brief The standard deviation of a geometrically distributed random + * variable X * @returns \sigma = \sqrt{V[X]} */ - float standard_deviation() const { - return std::sqrt(variance()); - } + float standard_deviation() const { return std::sqrt(variance()); } /** * @brief The probability density function @@ -95,7 +96,8 @@ public: /** * @brief The cumulative distribution function - * @details The sum of all probabilities up to (and including) k trials. Basically CDF(k) = P(x <= k) + * @details The sum of all probabilities up to (and including) k trials. + * Basically CDF(k) = P(x <= k) * @param k The number of trials in [1,\infty) * @returns The probability to have success within k trials */ @@ -105,8 +107,9 @@ public: /** * @brief The inverse cumulative distribution function - * @details This functions answers the question: Up to how many trials are needed to have success with a probability of cdf? - * The exact floating point value is reported. + * @details This functions answers the question: Up to how many trials are + * needed to have success with a probability of cdf? The exact floating + * point value is reported. * @param cdf The probability in [0,1] * @returns The number of (exact) trials. */ @@ -115,26 +118,37 @@ public: } /** - * @brief Generates a (discrete) sample according to the geometrical distribution + * @brief Generates a (discrete) sample according to the geometrical + * distribution * @returns A geometrically distributed number in [1,\infty) */ uint32_t draw_sample() const { float uniform_sample = generate_uniform(); - return static_cast(inverse_cumulative_distribution(uniform_sample)) + 1; + return static_cast( + inverse_cumulative_distribution(uniform_sample)) + + 1; } /** - * @brief This function computes the probability to have success in a given range of tries + * @brief This function computes the probability to have success in a given + * range of tries * @details Computes P(min_tries <= x <= max_tries). - * Can be used to calculate P(x >= min_tries) by not passing a second argument. - * Can be used to calculate P(x <= max_tries) by passing 1 as the first argument + * Can be used to calculate P(x >= min_tries) by not passing a second + * argument. Can be used to calculate P(x <= max_tries) by passing 1 as the + * first argument * @param min_tries The minimum number of tries in [1,\infty) (inclusive) - * @param max_tries The maximum number of tries in [min_tries, \infty) (inclusive) - * @returns The probability of having success within a range of tries [min_tries, max_tries] + * @param max_tries The maximum number of tries in [min_tries, \infty) + * (inclusive) + * @returns The probability of having success within a range of tries + * [min_tries, max_tries] */ - float range_tries(const uint32_t& min_tries = 1, const uint32_t& max_tries = std::numeric_limits::max()) const { + float range_tries(const uint32_t& min_tries = 1, + const uint32_t& max_tries = + std::numeric_limits::max()) const { float cdf_lower = cumulative_distribution(min_tries - 1); - float cdf_upper = max_tries == std::numeric_limits::max() ? 1.0f : cumulative_distribution(max_tries); + float cdf_upper = max_tries == std::numeric_limits::max() + ? 1.0f + : cumulative_distribution(max_tries); return cdf_upper - cdf_lower; } }; @@ -144,10 +158,12 @@ public: /** * @brief Tests the sampling method of the geometric distribution * @details Draws 1000000 random samples and estimates mean and variance - * These should be close to the expected value and variance of the given distribution to pass. + * These should be close to the expected value and variance of the given + * distribution to pass. * @param dist The distribution to test */ -void sample_test(const probability::geometric_dist::geometric_distribution& dist) { +void sample_test( + const probability::geometric_dist::geometric_distribution& dist) { uint32_t n_tries = 1000000; std::vector tries; tries.resize(n_tries); @@ -165,11 +181,13 @@ void sample_test(const probability::geometric_dist::geometric_distribution& dist var += (tries[i] - mean) * (tries[i] - mean); } - //Unbiased estimate of variance + // Unbiased estimate of variance var /= static_cast(n_tries - 1); - std::cout << "This value should be near " << dist.expected_value() << ": " << mean << std::endl; - std::cout << "This value should be near " << dist.variance() << ": " << var << std::endl; + std::cout << "This value should be near " << dist.expected_value() << ": " + << mean << std::endl; + std::cout << "This value should be near " << dist.variance() << ": " << var + << std::endl; } /** @@ -187,7 +205,9 @@ static void test() { assert(std::abs(dist.standard_deviation() - 2.788866755) < threshold); assert(std::abs(dist.probability_density(5) - 0.07203) < threshold); assert(std::abs(dist.cumulative_distribution(6) - 0.882351) < threshold); - assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution( + dist.cumulative_distribution(8)) - + 8) < threshold); assert(std::abs(dist.range_tries() - 1.0f) < threshold); assert(std::abs(dist.range_tries(3) - 0.49f) < threshold); assert(std::abs(dist.range_tries(5, 11) - 0.2203267f) < threshold); @@ -202,7 +222,9 @@ static void test() { assert(std::abs(dist.standard_deviation() - 1.4142135f) < threshold); assert(std::abs(dist.probability_density(5) - 0.03125) < threshold); assert(std::abs(dist.cumulative_distribution(6) - 0.984375) < threshold); - assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution( + dist.cumulative_distribution(8)) - + 8) < threshold); assert(std::abs(dist.range_tries() - 1.0f) < threshold); assert(std::abs(dist.range_tries(3) - 0.25f) < threshold); assert(std::abs(dist.range_tries(5, 11) - 0.062011f) < threshold); @@ -217,7 +239,9 @@ static void test() { assert(std::abs(dist.standard_deviation() - 0.559016f) < threshold); assert(std::abs(dist.probability_density(5) - 0.00128) < threshold); assert(std::abs(dist.cumulative_distribution(6) - 0.999936) < threshold); - assert(std::abs(dist.inverse_cumulative_distribution(dist.cumulative_distribution(8)) - 8) < threshold); + assert(std::abs(dist.inverse_cumulative_distribution( + dist.cumulative_distribution(8)) - + 8) < threshold); assert(std::abs(dist.range_tries() - 1.0f) < threshold); assert(std::abs(dist.range_tries(3) - 0.04f) < threshold); assert(std::abs(dist.range_tries(5, 11) - 0.00159997f) < threshold); diff --git a/probability/windowed_median.cpp b/probability/windowed_median.cpp index 8945b063e..52c70ae24 100644 --- a/probability/windowed_median.cpp +++ b/probability/windowed_median.cpp @@ -4,8 +4,8 @@ * data stream * * @details - * Given a stream of integers, the algorithm calculates the median of a fixed size - * window at the back of the stream. The leading time complexity of this + * Given a stream of integers, the algorithm calculates the median of a fixed + * size window at the back of the stream. The leading time complexity of this * algorithm is O(log(N), and it is inspired by the known algorithm to [find * median from (infinite) data * stream](https://www.tutorialcup.com/interview/algorithm/find-median-from-data-stream.htm), @@ -17,13 +17,13 @@ * pushing and popping. Each new value is pushed to the window back, while a * value from the front of the window is popped. In addition, the algorithm * manages a multi-value binary search tree (BST), implemented by std::multiset. - * For each new value that is inserted into the window, it is also inserted to the - * BST. When a value is popped from the window, it is also erased from the BST. - * Both insertion and erasion to/from the BST are O(logN) in time, with N the - * size of the window. Finally, the algorithm keeps a pointer to the root of the - * BST, and updates its position whenever values are inserted or erased to/from - * BST. The root of the tree is the median! Hence, median retrieval is always - * O(1) + * For each new value that is inserted into the window, it is also inserted to + * the BST. When a value is popped from the window, it is also erased from the + * BST. Both insertion and erasion to/from the BST are O(logN) in time, with N + * the size of the window. Finally, the algorithm keeps a pointer to the root of + * the BST, and updates its position whenever values are inserted or erased + * to/from BST. The root of the tree is the median! Hence, median retrieval is + * always O(1) * * Time complexity: O(logN). Space complexity: O(N). N - size of window * @author [Yaniv Hollander](https://github.com/YanivHollander) @@ -32,8 +32,8 @@ #include /// for std::rand - needed in testing #include /// for std::time - needed in testing #include /// for std::list - used to manage sliding window -#include /// for std::multiset - used to manage multi-value sorted sliding window values -#include /// for std::vector - needed in testing +#include /// for std::multiset - used to manage multi-value sorted sliding window values +#include /// for std::vector - needed in testing /** * @namespace probability @@ -55,7 +55,7 @@ using size_type = Window::size_type; */ class WindowedMedian { const size_type _windowSize; ///< sliding window size - Window _window; ///< a sliding window of values along the stream + Window _window; ///< a sliding window of values along the stream std::multiset _sortedValues; ///< a DS to represent a balanced /// multi-value binary search tree (BST) std::multiset::const_iterator @@ -103,13 +103,14 @@ class WindowedMedian { } /// However, if the erased value is on the right branch or the median - /// itself, and the number of elements is odd, the new median will be the - /// left child of the current one + /// itself, and the number of elements is odd, the new median will be + /// the left child of the current one else if (value >= *_itMedian && sz % 2 != 0) { --_itMedian; // O(1) - traversing one step to the left child } - /// Find the (first) position of the value we want to erase, and erase it + /// Find the (first) position of the value we want to erase, and erase + /// it const auto it = _sortedValues.find(value); // O(logN) _sortedValues.erase(it); // O(logN) } @@ -126,16 +127,16 @@ class WindowedMedian { * @param value New value to insert */ void insert(int value) { - /// Push new value to the back of the sliding window - O(1) _window.push_back(value); insertToSorted(value); // Insert value to the multi-value BST - O(logN) - if (_window.size() > _windowSize) { /// If exceeding size of window, pop - /// from its left side - eraseFromSorted(_window.front()); /// Erase from the multi-value BST - /// the window left side value - _window - .pop_front(); /// Pop the left side value from the window - O(1) + if (_window.size() > _windowSize) { /// If exceeding size of window, + /// pop from its left side + eraseFromSorted( + _window.front()); /// Erase from the multi-value BST + /// the window left side value + _window.pop_front(); /// Pop the left side value from the window - + /// O(1) } } @@ -170,8 +171,8 @@ class WindowedMedian { 0.5f * *next(window.begin(), window.size() / 2 - 1); /// O(N) } }; -} /// namespace windowed_median -} /// namespace probability +} // namespace windowed_median +} // namespace probability /** * @brief Self-test implementations @@ -195,32 +196,41 @@ static void test(const std::vector &vals, int windowSize) { * @returns 0 on exit */ int main(int argc, const char *argv[]) { - /// A few fixed test cases - test({1, 2, 3, 4, 5, 6, 7, 8, 9}, 3); /// Array of sorted values; odd window size - test({9, 8, 7, 6, 5, 4, 3, 2, 1}, 3); /// Array of sorted values - decreasing; odd window size - test({9, 8, 7, 6, 5, 4, 5, 6}, 4); /// Even window size - test({3, 3, 3, 3, 3, 3, 3, 3, 3}, 3); /// Array with repeating values - test({3, 3, 3, 3, 7, 3, 3, 3, 3}, 3); /// Array with same values except one - test({4, 3, 3, -5, -5, 1, 3, 4, 5}, 5); /// Array that includes repeating values including negatives - - /// Array with large values - sum of few pairs exceeds MAX_INT. Window size is even - testing calculation of - /// average median between two middle values + test({1, 2, 3, 4, 5, 6, 7, 8, 9}, + 3); /// Array of sorted values; odd window size + test({9, 8, 7, 6, 5, 4, 3, 2, 1}, + 3); /// Array of sorted values - decreasing; odd window size + test({9, 8, 7, 6, 5, 4, 5, 6}, 4); /// Even window size + test({3, 3, 3, 3, 3, 3, 3, 3, 3}, 3); /// Array with repeating values + test({3, 3, 3, 3, 7, 3, 3, 3, 3}, 3); /// Array with same values except one + test({4, 3, 3, -5, -5, 1, 3, 4, 5}, + 5); /// Array that includes repeating values including negatives + + /// Array with large values - sum of few pairs exceeds MAX_INT. Window size + /// is even - testing calculation of average median between two middle + /// values test({470211272, 101027544, 1457850878, 1458777923, 2007237709, 823564440, - 1115438165, 1784484492, 74243042, 114807987}, 6); - + 1115438165, 1784484492, 74243042, 114807987}, + 6); + /// Random test cases std::srand(static_cast(std::time(nullptr))); std::vector vals; for (int i = 8; i < 100; i++) { - const auto n = 1 + std::rand() / ((RAND_MAX + 5u) / 20); /// Array size in the range [5, 20] - auto windowSize = 1 + std::rand() / ((RAND_MAX + 3u) / 10); /// Window size in the range [3, 10] + const auto n = + 1 + std::rand() / + ((RAND_MAX + 5u) / 20); /// Array size in the range [5, 20] + auto windowSize = + 1 + std::rand() / ((RAND_MAX + 3u) / + 10); /// Window size in the range [3, 10] vals.clear(); vals.reserve(n); for (int i = 0; i < n; i++) { - vals.push_back(rand() - RAND_MAX); /// Random array values (positive/negative) + vals.push_back( + rand() - RAND_MAX); /// Random array values (positive/negative) } - test(vals, windowSize); /// Testing randomized test + test(vals, windowSize); /// Testing randomized test } return 0; } diff --git a/search/text_search.cpp b/search/text_search.cpp index ee66a506a..291b1df85 100644 --- a/search/text_search.cpp +++ b/search/text_search.cpp @@ -2,6 +2,7 @@ * \file * \brief Search for words in a long textual paragraph. */ +#include #include #include #ifdef _MSC_VER @@ -10,9 +11,38 @@ #include #endif -/** Main function +/** + * @brief function to convert a C++ string to lower case + * @param word takes an std::string as input + * @returns std::string + */ +std::string lower(std::string word) { + int length = word.length(); + std::string lc = ""; + + for (int i = 0; i < length; i++) { + lc += tolower(word[i]); + } + + return lc; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + assert(lower("abcd").compare("abcd") == 0); + assert(lower("abc").compare("abcd") == -1); + assert(lower("abcd").compare("abc") == 1); +} + +/** + * @brief Main function + * @returns 0 on exit */ int main() { + test(); // run self-test implementations std::string paragraph; std::cout << "Please enter your paragraph: \n"; std::getline(std::cin, paragraph); @@ -23,20 +53,46 @@ int main() { if (paragraph.empty()) { std::cout << "\nThe paragraph is empty" << std::endl; } else { + int ch = 0; while (true) { std::string word; std::cout << "Please enter the word you are searching for: "; std::getline(std::cin, word); - std::cout << "Hello, your word is " << word << "!\n"; - if (paragraph.find(word) == std::string::npos) { - std::cout << word << " does not exist in the sentence" - << std::endl; + std::cout << "Ignore case-sensitive? 1 = Yes, 0 = No" << std::endl; + std::cin >> ch; + if (ch == 1) { + std::string lowerCase = lower( + paragraph); // convert std::string paragraph to lowercase + // and store it in std::string lowerCase + std::string lowerCaseWord = + lower(word); // convert std::string paragraph to lowercase + // and store it in std::string lowerCase + + std::cout << "Hello, your word is " << word << "!\n"; + if (lowerCase.find(lowerCaseWord) == std::string::npos) { + std::cout << word << " does not exist in the sentence" + << std::endl; + } else { + std::cout << "The word " << word + << " is now found at location " + << lowerCase.find(lowerCaseWord) << std::endl + << std::endl; + } } else { - std::cout << "The word " << word << " is now found at location " - << paragraph.find(word) << std::endl - << std::endl; + std::cout << "Hello, your word is " << word << "!\n"; + if (paragraph.find(word) == std::string::npos) { + std::cout << word << " does not exist in the sentence" + << std::endl; + } else { + std::cout << "The word " << word + << " is now found at location " + << paragraph.find(word) << std::endl + << std::endl; + } } + std::cout << "\nPress Ctrl + C to exit the program.\n\n"; std::cin.get(); } } + return 0; } From 229260698981eebc4ffc015a2327bb57bee2cced Mon Sep 17 00:00:00 2001 From: Abhijeet Tiwari <85331806+thisabhijeet@users.noreply.github.com> Date: Fri, 15 Oct 2021 21:45:53 +0530 Subject: [PATCH 05/15] feat: kadane's algorithm added (#1669) * feat: kadane's algorithm added * file renamed to kadanes3.cpp and clang-tidy warnings fixed * updating DIRECTORY.md * DIRECTORY.md and kadanes3.cpp modified * change integer types to int64_t and uint64_t, as per the requirements. * clang-format and clang-tidy fixes for 5025b93a * Apply suggestions from code review Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + others/kadanes3.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 others/kadanes3.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 6c6e7711e..c6ea201b5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -248,6 +248,7 @@ * [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) + * [Kadanes3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/kadanes3.cpp) * [Lru Cache](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/lru_cache.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) diff --git a/others/kadanes3.cpp b/others/kadanes3.cpp new file mode 100644 index 000000000..9cc6604e9 --- /dev/null +++ b/others/kadanes3.cpp @@ -0,0 +1,86 @@ +/** + * @file + * @brief Efficient implementation for maximum contiguous subarray sum by + * [Kadane's + * algorithm](https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/). + * @details + * Our task is to take length of array and then the whole array as input from + * the user and then calculate the maximum contiguos subarray sum for the + * input array, using the kadane's algorithm. + * + * There can be a case that all the elements in the input array are negative. + * In that case, the least value among all elements is the maximum sum with + * subarray length = 1. + * @author [Abhijeet Tiwari](https://github.com/thisabhijeet) + */ + +#include /// for std::array +#include /// for assert +#include /// for INT_MIN value +#include /// for IO operations + +/** + * @brief Utility function to check the current maximum number + * \param arr input array + * \param length length of the input array + * \returns maximum contiguous subarray sum + */ +template +int max_subarray_sum(std::array arr, uint64_t length) { + int64_t current_max = INT_MIN, current_sum = 0; + for (int i = 0; i < length; i++) { + current_sum = current_sum + arr[i]; + if (current_max < current_sum) { + current_max = current_sum; + } + + if (current_sum < 0) { + current_sum = 0; + } + } + return current_max; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + std::array arr = {1, 2, 3, 4}; + std::array arr1 = {-1, -2, -4, -6, 7}; + assert(max_subarray_sum(arr, 4) == 10); + assert(max_subarray_sum(arr1, 5) == 7); + std::cout << "All test cases have passed!\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + // Below is the code for accepting array from the user and then + // calling the function for the required output. + // It has been commented for now so that the test() function can run + // and the test cases can be verified. + // code for accepting array from user starts + + // std::size_t n; // variable for length of input array + // std::cout << "Enter length of the array: "; + // std::cin >> n; + // std::array arr = {0}; + // // we need to give a constant in size. Hence we have allocated 100 + // for now. + // for (int i = 0; i < n; i++) + // taking input of each element of the array + // { + // std::cin >> arr[i]; + // } + // code for accepting array from user ends + + // int max_sum = max_subarray_sum(arr, n); + // std::cout << "Maximum contiguous sum for this array is : " << max_sum + // << std::endl; + + test(); // run self-test implementations + return 0; +} From bbec149f6dbee08cfd95f6dcbf27cdea1e65727a Mon Sep 17 00:00:00 2001 From: Paulo Vitor Lima Borges <31678236+PauloVLB@users.noreply.github.com> Date: Fri, 15 Oct 2021 13:17:10 -0300 Subject: [PATCH 06/15] feat: add prefix sum array data structure (#1663) * feat: add prefix sum array data structure * feat: add prefix_sum_array data structure * updating DIRECTORY.md * feat: Add Prefix Sum Array datastructure * feat: Add Prefix Sum Array data structure * Update range_queries/prefix_sum_array.cpp Co-authored-by: David Leal * Update prefix_sum_array.cpp * Update prefix_sum_array.cpp * Update range_queries/prefix_sum_array.cpp Co-authored-by: David Leal * Update range_queries/prefix_sum_array.cpp Co-authored-by: David Leal * Update range_queries/prefix_sum_array.cpp Co-authored-by: David Leal * Update range_queries/prefix_sum_array.cpp * Update range_queries/prefix_sum_array.cpp Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + range_queries/prefix_sum_array.cpp | 83 ++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 range_queries/prefix_sum_array.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index c6ea201b5..207692b7e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -276,6 +276,7 @@ * [Heavy Light Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/heavy_light_decomposition.cpp) * [Mo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/mo.cpp) * [Persistent Seg Tree Lazy Prop](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/persistent_seg_tree_lazy_prop.cpp) + * [Prefix Sum Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/prefix_sum_array.cpp) * [Segtree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/segtree.cpp) * [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/sparse_table.cpp) diff --git a/range_queries/prefix_sum_array.cpp b/range_queries/prefix_sum_array.cpp new file mode 100644 index 000000000..1ddb90eaf --- /dev/null +++ b/range_queries/prefix_sum_array.cpp @@ -0,0 +1,83 @@ +/** + * @file + * @brief + * [Prefix Sum + * Array](https://en.wikipedia.org/wiki/Prefix_sum) data structure + * implementation. + * + * @details + * Prefix Sum Array is a data structure, that allows answering sum in some range + * queries. It can answer most sum range queries in O(1), with a build time + * complexity of O(N). But it hasn't an update querie. + * + * * Running Time Complexity \n + * * Build : O(N) \n + * * Range Query : O(1) \n + * @author [Paulo Vitor Lima Borges](https://github.com/PauloVLB) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace range_queries + * @brief Range Queries algorithms + */ +namespace range_queries { +/** + * @namespace prefix_sum_array + * @brief Range sum queries using prefix-sum-array + */ +namespace prefix_sum_array { + +std::vector PSA(1, 0); + +/** + * @brief function that builds the PSA + * @param original_array original array of values + * @returns void + */ +void build(std::vector original_array) { + for (int i = 1; i <= static_cast(original_array.size()); i++) { + PSA.push_back(PSA[i - 1] + original_array[i]); + } +} +/** + * @brief query function + * @param beg begin of the interval to sum + * @param end end of the interval to sum + * @returns sum of the range [beg, end] + */ +int64_t query(int64_t beg, int64_t end) { return PSA[end] - PSA[beg - 1]; } + +} // namespace prefix_sum_array +} // namespace range_queries + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + std::vector values{0, 123, 0, 2, -2, 5, + 24, 0, 23, -1, -1}; // original array + + range_queries::prefix_sum_array::build(values); + // queries are of the type: sum of the range [a, b] = psa[b] - psa[a-1] + + assert(range_queries::prefix_sum_array::query(1, 10) == + 173); // sum of the entire array + assert(range_queries::prefix_sum_array::query(4, 6) == + 27); // the sum of the interval [4, 6] + assert(range_queries::prefix_sum_array::query(5, 9) == + 51); // the sum of the interval [5, 9] +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 95ed72a45275da29096e3bc1da83ae72fa98c4a9 Mon Sep 17 00:00:00 2001 From: Pratyush219 <53852042+Pratyush219@users.noreply.github.com> Date: Fri, 15 Oct 2021 22:04:00 +0530 Subject: [PATCH 07/15] feat: Added implementation of FCFS CPU scheduling algorithm (#1684) * FCFS scheduling algorithm in operating system Added C++ implementation of FCFS scheduling algorithm in a new directory Operating-System/Scheduing-Algorithms * Renamed files and directories to match guidelines * Updated comments * Added comments for member variables of FCFS class * Deleted .vscode directory * Replaced array of tuples with vector of tuples Replaced formatted printf with cout and iomanip flags Removed unused code blocks * Replaced array of tuples with vector of tuples * Removed nested directory * updating DIRECTORY.md * clang-format and clang-tidy fixes for c95495b4 * clang-format and clang-tidy fixes for 732f247d * Updated the documentation and used unsigned int for non-negative integers * clang-format and clang-tidy fixes for 295f0cc6 * clang-format and clang-tidy fixes for 31f05910 * Added test cases using random number generator * Replaced time(0) with time(nullptr) * clang-format and clang-tidy fixes for 40d663d3 * Fixed documentation * Rearranged code * clang-format and clang-tidy fixes for b40a2801 * clang-format and clang-tidy fixes for 243dcc15 * Updated documentation * clang-format and clang-tidy fixes for 899ff7ea * Fixed some typos * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Replaced int with uint32_t in lines 259 and 263 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 3 + cpu_scheduling_algorithms/fcfs_scheduling.cpp | 290 ++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 cpu_scheduling_algorithms/fcfs_scheduling.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 207692b7e..84a3b276f 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -29,6 +29,9 @@ * [Vigenere Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/vigenere_cipher.cpp) * [Xor Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/xor_cipher.cpp) +## Cpu Scheduling Algorithms + * [Fcfs Scheduling](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/cpu_scheduling_algorithms/fcfs_scheduling.cpp) + ## Data Structures * [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/avltree.cpp) * [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/binary_search_tree.cpp) diff --git a/cpu_scheduling_algorithms/fcfs_scheduling.cpp b/cpu_scheduling_algorithms/fcfs_scheduling.cpp new file mode 100644 index 000000000..4fc61af6b --- /dev/null +++ b/cpu_scheduling_algorithms/fcfs_scheduling.cpp @@ -0,0 +1,290 @@ +/** + * @file + * @brief Implementation of FCFS CPU scheduling algorithm + * @details + * FCFS is a non-preemptive CPU scheduling algorithm in which whichever process + * arrives first, gets executed first. If two or more processes arrive + * simultaneously, the process with smaller process ID gets executed first. + * @link https://bit.ly/3ABNXOC + * @author [Pratyush Vatsa](https://github.com/Pratyush219) + */ + +#include /// for sorting +#include /// for assert +#include /// random number generation +#include /// for time +#include /// for formatting the output +#include /// for IO operations +#include /// for std::priority_queue +#include /// for std::unordered_set +#include /// for std::vector + +using std::cin; +using std::cout; +using std::endl; +using std::get; +using std::left; +using std::make_tuple; +using std::priority_queue; +using std::rand; +using std::srand; +using std::tuple; +using std::unordered_set; +using std::vector; +/** + * @brief Comparator function for sorting a vector + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + * @param t1 First tuple + * @param t2 Second tuple + * @returns true if t1 and t2 are in the CORRECT order + * @returns false if t1 and t2 are in the INCORRECT order + */ +template +bool sortcol(tuple& t1, tuple& t2) { + if (get<1>(t1) < get<1>(t2)) { + return true; + } else if (get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2)) { + return true; + } + return false; +} + +/** + * @class Compare + * @brief Comparator class for priority queue + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + */ +template +class Compare { + public: + /** + * @param t1 First tuple + * @param t2 Second tuple + * @brief A comparator function that checks whether to swap the two tuples + * or not. + * @link Refer to + * https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/ for + * detailed description of comparator + * @returns true if the tuples SHOULD be swapped + * @returns false if the tuples SHOULDN'T be swapped + */ + bool operator()(tuple& t1, + tuple& t2) { + // Compare arrival times + if (get<1>(t2) < get<1>(t1)) { + return true; + } + // If arrival times are same, then compare Process IDs + else if (get<1>(t2) == get<1>(t1)) { + return get<0>(t2) < get<0>(t1); + } + return false; + } +}; + +/** + * @class FCFS + * @brief Class which implements the FCFS scheduling algorithm + * @tparam S Data type of Process ID + * @tparam T Data type of Arrival time + * @tparam E Data type of Burst time + */ +template +class FCFS { + /** + * Priority queue of schedules(stored as tuples) of processes. + * In each tuple + * 1st element: Process ID + * 2nd element: Arrival Time + * 3rd element: Burst time + * 4th element: Completion time + * 5th element: Turnaround time + * 6th element: Waiting time + */ + priority_queue, + vector>, + Compare> + schedule; + + // Stores final status of all the processes after completing the execution. + vector> result; + + // Stores process IDs. Used for confirming absence of a process while adding + // it. + unordered_set idList; + + public: + /** + * @brief Adds the process to the ready queue if it isn't already there + * @param id Process ID + * @param arrival Arrival time of the process + * @param burst Burst time of the process + * @returns void + * + */ + void addProcess(S id, T arrival, E burst) { + // Add if a process with process ID as id is not found in idList. + if (idList.find(id) == idList.end()) { + tuple t = + make_tuple(id, arrival, burst, 0, 0, 0); + schedule.push(t); + idList.insert(id); + } + } + + /** + * @brief Algorithm for scheduling CPU processes according to the First Come + * First Serve(FCFS) scheduling algorithm. + * + * @details FCFS is a non-preemptive algorithm in which the process which + * arrives first gets executed first. If two or more processes arrive + * together then the process with smaller process ID runs first (each + * process has a unique proces ID). + * + * I used a min priority queue of tuples to accomplish this task. The + * processes are ordered by their arrival times. If arrival times of some + * processes are equal, then they are ordered by their process ID. + * + * @returns void + */ + vector> scheduleForFcfs() { + // Variable to keep track of time elapsed so far + double timeElapsed = 0; + + while (!schedule.empty()) { + tuple cur = schedule.top(); + + // If the current process arrived at time t2, the last process + // completed its execution at time t1, and t2 > t1. + if (get<1>(cur) > timeElapsed) { + timeElapsed += get<1>(cur) - timeElapsed; + } + + // Add Burst time to time elapsed + timeElapsed += get<2>(cur); + + // Completion time of the current process will be same as time + // elapsed so far + get<3>(cur) = timeElapsed; + + // Turnaround time = Completion time - Arrival time + get<4>(cur) = get<3>(cur) - get<1>(cur); + + // Waiting time = Turnaround time - Burst time + get<5>(cur) = get<4>(cur) - get<2>(cur); + + result.push_back(cur); + schedule.pop(); + } + return result; + } + + /** + * @brief Utility function for printing the status of each process after + * execution + * @returns void + */ + void printResult() { + cout << "Status of all the proceses post completion is as follows:" + << endl; + + cout << std::setw(17) << left << "Process ID" << std::setw(17) << left + << "Arrival Time" << std::setw(17) << left << "Burst Time" + << std::setw(17) << left << "Completion Time" << std::setw(17) + << left << "Turnaround Time" << std::setw(17) << left + << "Waiting Time" << endl; + + for (size_t i{}; i < result.size(); i++) { + cout << std::setprecision(2) << std::fixed << std::setw(17) << left + << get<0>(result[i]) << std::setw(17) << left + << get<1>(result[i]) << std::setw(17) << left + << get<2>(result[i]) << std::setw(17) << left + << get<3>(result[i]) << std::setw(17) << left + << get<4>(result[i]) << std::setw(17) << left + << get<5>(result[i]) << endl; + } + } +}; + +/** + * @brief Function to be used for testing purposes. This function guarantees the + * correct solution for FCFS scheduling algorithm. + * @param input the input data + * @details Sorts the input vector according to arrival time. Processes whose + * arrival times are same get sorted according to process ID For each process, + * completion time, turnaround time and completion time are calculated, inserted + * in a tuple, which is added to the vector result. + * @returns A vector of tuples consisting of process ID, arrival time, burst + * time, completion time, turnaround time and waiting time for each process. + */ +template +vector> get_final_status( + vector> input) { + sort(input.begin(), input.end(), sortcol); + vector> result(input.size()); + double timeElapsed = 0; + for (size_t i{}; i < input.size(); i++) { + T arrival = get<1>(input[i]); + E burst = get<2>(input[i]); + + if (arrival > timeElapsed) { + timeElapsed += arrival - timeElapsed; + } + timeElapsed += burst; + double completion = timeElapsed; + double turnaround = completion - arrival; + double waiting = turnaround - burst; + + get<0>(result[i]) = get<0>(input[i]); + get<1>(result[i]) = arrival; + get<2>(result[i]) = burst; + get<3>(result[i]) = completion; + get<4>(result[i]) = turnaround; + get<5>(result[i]) = waiting; + } + return result; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + for (int i{}; i < 1000; i++) { + srand(time(nullptr)); + uint32_t n = 1 + rand() % 1000; + FCFS readyQueue; + vector> input(n); + + for (uint32_t i{}; i < n; i++) { + get<0>(input[i]) = i; + srand(time(nullptr)); + get<1>(input[i]) = 1 + rand() % 10000; + srand(time(nullptr)); + get<2>(input[i]) = 1 + rand() % 10000; + } + + for (uint32_t i{}; i < n; i++) { + readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]), + get<2>(input[i])); + } + vector> + res = get_final_status(input); + assert(res == readyQueue.scheduleForFcfs()); + // readyQueue.printResult(); + } + cout << "All the tests have successfully passed!" << endl; +} + +/** + * @brief Entry point of the program + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From a9882e6f259f91dd8d44d08ffbb0c52861bf863e Mon Sep 17 00:00:00 2001 From: AlternateWalls <71268229+AlternateWalls@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:05:54 -0400 Subject: [PATCH 08/15] [feat/fix/docs]: Improve the Easter Determination algorithm (#1675) * Create easter.cpp * Update easter.cpp * Update easter.cpp * Update easter.cpp * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * updating DIRECTORY.md * clang-format and clang-tidy fixes for f8e4e3fb * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * Update others/easter.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for aae0d475 * Update easter.cpp * Update easter.cpp * clang-format and clang-tidy fixes for e033f98f Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 + others/easter.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 others/easter.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 84a3b276f..53e2090ab 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -248,6 +248,7 @@ * [Decimal To Binary](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_binary.cpp) * [Decimal To Hexadecimal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_hexadecimal.cpp) * [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp) + * [Easter](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/easter.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) diff --git a/others/easter.cpp b/others/easter.cpp new file mode 100644 index 000000000..36ac48028 --- /dev/null +++ b/others/easter.cpp @@ -0,0 +1,109 @@ +/* + * @file + * @brief Determines the [Date of + * Easter](https://en.wikipedia.org/wiki/Date_of_Easter) after 1582 + * + * @details + * The date of Easter is determined in each year through a calculation known as + * "computus." Easter is celebrated on the first Sunday after the Paschal full + * moon, which is the first full moon on or after 21 March. Determining this + * date in advance requires a correlation between the lunar months and the solar + * year, while also accounting for the month, date, and weekday of the Julian or + * Gregorian calendar. The complexity of the algorithm arises because of the + * desire to associate the date of Easter with the date of the Jewish feast of + * Passover which, Christians believe, is when Jesus was crucified. + * + * + * @author [AlternateWalls](https://github.com/AlternateWalls) + */ + +#include /// for assert +#include /// for IO operations + +/* + * @brief Contains information for Easter date + */ +class EasterYearMonthDay { + public: + uint64_t year; ///< year Easter is on + uint64_t month; ///< month Easter is on + uint64_t day; ///< day Easter is on + + EasterYearMonthDay(uint64_t newYear, uint64_t newMonth, uint64_t newDay) { + year = newYear; // Assigns year to class + month = newMonth; + day = newDay; + } +}; + +/* + * @brief Function that finds the month and day of Easter + * @params param1 An int "y" of the year you want to find Easter on after + * 1582 + * @returns An instance of the easterYearMonthDay calss that contains the + * information (Ex. 420 - 4/20 or April 20th) + */ +EasterYearMonthDay findEaster(uint64_t y) { + if (y > 1582) { + uint64_t a = y % 19; // Year's location on Metonic Calendar + uint64_t b = y / 100; // Century index + uint64_t c = y % 100; + uint64_t d = b / 4; + uint64_t e = b % 4; // Takes into account leap years + uint64_t f = (b + 8) / 25; + uint64_t g = (b - f + 1) / 3; + uint64_t h = (19 * a + b - d - g + 15) % + 30; // Days from Mar. 21st until the full moon + uint64_t i = c / 4; + uint64_t k = c % 4; + uint64_t r = + (32 + 2 * e + 2 * i - h - k) % + 7; // The number of days from Paschal full moon to next Sunday + uint64_t m = (a + 11 * h + 22 * r) / 451; + uint64_t n = (h + r - 7 * m + 114) / 31; // Month of Easter + uint64_t p = (h + r - 7 * m + 114) % 31; // p + 1 is the day of Easter + + // Assign values + EasterYearMonthDay date( + y, n, p + 1); // Assign values to new instance of class + + // Return date + return date; + } else { + EasterYearMonthDay date(0, 0, 0); + + // Return date + return date; + } +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 2003 | April 20th + assert(findEaster(2003).month == 4); // Should return true + assert(findEaster(2003).day == 20); // Should return true + + // 1910 | March 27th + assert(findEaster(1910).month == 3); // Should return true + assert(findEaster(1910).day == 27); // Should return true + + // 1877 | April 1st + assert(findEaster(1877).month != 3); // Should return true + assert(findEaster(1877).day != 22); // Should return true + + // 1400 | Invalid date + assert(findEaster(1400).month == 0); // Should return true + assert(findEaster(1400).day == 0); // Should return true +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 27f1ed312f4f566591ae8be744006de0b08cd331 Mon Sep 17 00:00:00 2001 From: Domenic Zingsheim Date: Sat, 16 Oct 2021 01:34:15 +0000 Subject: [PATCH 09/15] feat: Add integral approximation using Monte Carlo Integration (#1742) * feat: Add monte carlo integration * test: Add tests for monte carlo integration * docs: Add documentation for monte carlo integration * updating DIRECTORY.md * fix: Add _USE_MATH_DEFINES for windows * fix: Comment spacing Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + math/integral_approximation2.cpp | 196 +++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 math/integral_approximation2.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 53e2090ab..d1822f7cf 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -182,6 +182,7 @@ * [Gcd Of N Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/gcd_of_n_numbers.cpp) * [Gcd Recursive Euclidean](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/gcd_recursive_euclidean.cpp) * [Integral Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/integral_approximation.cpp) + * [Integral Approximation2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/integral_approximation2.cpp) * [Inv Sqrt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/inv_sqrt.cpp) * [Large Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/large_factorial.cpp) * [Large Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/large_number.h) diff --git a/math/integral_approximation2.cpp b/math/integral_approximation2.cpp new file mode 100644 index 000000000..706672d12 --- /dev/null +++ b/math/integral_approximation2.cpp @@ -0,0 +1,196 @@ +/** + * @file + * @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. + * + * 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. + * + * @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 + +/** + * @namespace math + * @brief Math algorithms + */ +namespace math { +/** + * @namespace monte_carlo + * @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 + +/** + * @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 + * 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 + */ +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); + + double x_t = start_point; + + std::default_random_engine generator; + std::uniform_real_distribution uniform(0.0, 1.0); + std::normal_distribution normal(0.0, 1.0); + generator.seed(time(nullptr)); + + 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 u = uniform(generator); + + // Accept "new state" according to the acceptance_probability + if(u <= acceptance_probability) { + x_t = x_dash; + } + + if(t >= discard) { + samples.push_back(x_t); + } + } + + return samples; +} + +/** + * @brief Compute an approximation of an integral using Monte Carlo integration + * @details The integration domain [a,b] is given by the pdf. + * The pdf has to fulfill the following conditions: + * 1) for all x \in [a,b] : p(x) > 0 + * 2) for all x \not\in [a,b] : p(x) = 0 + * 3) \int_a^b p(x) dx = 1 + * @param start_point The start point of the Markov Chain (see generate_samples) + * @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) + */ +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); + + for(double sample : samples) { + integral += function(sample) / pdf(sample); + } + + return integral / static_cast(samples.size()); +} + +} // namespace monte_carlo +} // namespace math + +/** + * @brief Self-test implementations + * @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;; + + math::monte_carlo::Function f; + math::monte_carlo::Function pdf; + double integral = 0; + double lower_bound = 0, upper_bound = 0; + + /* \int_{-2}^{2} -x^2 + 4 dx */ + 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) { + return 0.1; + } + if(x <= upper_bound && x >= 1.0) { + return 0.1; + } + 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); + + 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); + }; + + lower_bound = 0.0; + upper_bound = 1.0; + pdf = [&](double& x) { + if(x >= lower_bound && x <= 0.2) { + return 0.1; + } + if(x > 0.2 && x <= 0.4) { + return 0.4; + } + 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); + + 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); + }; + + pdf = [&](double& x) { + return 1.0 / std::sqrt(2.0 * M_PI) * std::exp(-x * x / 2.0); + }; + + 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; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 6272b2af084953471348442c79e19a6030c18427 Mon Sep 17 00:00:00 2001 From: Prashant Thakur Date: Sun, 17 Oct 2021 06:27:23 +0530 Subject: [PATCH 10/15] feat: Modified count_set_bits.cpp (#1634) * Modified: Replaced existing code with faster implementation * Changed long long to "int64_t" * Indentation Fixed. * Modified Documentation. * Updated authors of count_set_bits.cpp Co-authored-by: David Leal * Apply suggestions from code review Co-authored-by: David Leal * Added proper indentation in "main" function Co-authored-by: David Leal Co-authored-by: David Leal --- bit_manipulation/count_of_set_bits.cpp | 51 +++++++++++++------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/bit_manipulation/count_of_set_bits.cpp b/bit_manipulation/count_of_set_bits.cpp index 87f01d161..497346a53 100644 --- a/bit_manipulation/count_of_set_bits.cpp +++ b/bit_manipulation/count_of_set_bits.cpp @@ -1,26 +1,21 @@ /** * @file - * @brief Implementation to [count sets - * bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an + * @brief Implementation to [count number of set bits of a number] + * (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. + * We are given an integer number. We need to calculate the number of set bits in it. * - * 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) + * A binary number consists of two digits. They are 0 & 1. Digit 1 is known as + * set bit in computer terms. + * Worst Case Time Complexity: O(log n) * Space complexity: O(1) * @author [Swastika Gupta](https://github.com/Swastyy) + * @author [Prashant Thakur](https://github.com/prashant-th18) */ - #include /// for assert -#include /// for io operations -#include /// for std::vector - +#include /// for IO operations /** * @namespace bit_manipulation * @brief Bit manipulation algorithms @@ -36,24 +31,27 @@ 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` + * @returns total number of set-bits in the binary representation of number `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 +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) + { + ++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!! } } // 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); @@ -67,9 +65,12 @@ static void test() { assert(bit_manipulation::count_of_set_bits::countSetBits(15) == 4); // n = 25 return 3 assert(bit_manipulation::count_of_set_bits::countSetBits(25) == 3); + // n = 97 return 3 + assert(bit_manipulation::count_of_set_bits::countSetBits(97) == 3); + // n = 31 return 5 + assert(bit_manipulation::count_of_set_bits::countSetBits(31) == 5); std::cout << "All test cases successfully passed!" << std::endl; } - /** * @brief Main function * @returns 0 on exit From 72e88b30cd6534016f1556d5cb82acfa5e68f2e6 Mon Sep 17 00:00:00 2001 From: Tushar Mohan Date: Mon, 18 Oct 2021 20:12:16 +0530 Subject: [PATCH 11/15] feat : Implementation of stack using queue with C++ STL (#1719) * implementation of stack using queue with C++ STL * fix: documentation + code formatting * updating DIRECTORY.md * fix: changes asked * fix : made the required changes * fix : required changes * fix : -is on line 38 * fix : requested changes: * fix : self-tests added * fix: structure of tests * fix : requested changes * fix : requested changes * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: RahulSethi070801 <55681359+RahulSethi070801@users.noreply.github.com> --- DIRECTORY.md | 1 + data_structures/stack_using_queue.cpp | 126 ++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 data_structures/stack_using_queue.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index d1822f7cf..3f55016aa 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -61,6 +61,7 @@ * [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack.h) * [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_array.cpp) * [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_linked_list.cpp) + * [Stack Using Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_queue.cpp) * [Test Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_queue.cpp) * [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack.cpp) * [Test Stack Students](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack_students.cpp) diff --git a/data_structures/stack_using_queue.cpp b/data_structures/stack_using_queue.cpp new file mode 100644 index 000000000..54a81a135 --- /dev/null +++ b/data_structures/stack_using_queue.cpp @@ -0,0 +1,126 @@ +/** + * @brief Stack Data Structure Using the Queue Data Structure + * @details + * Using 2 Queues inside the Stack class, we can easily implement Stack + * data structure with heavy computation in push function. + * + * References used: [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) + * @author [tushar2407](https://github.com/tushar2407) + */ +#include /// for IO operations +#include /// for queue data structure +#include /// for assert + +/** + * @namespace data_strcutres + * @brief Data structures algorithms + */ +namespace data_structures { +/** + * @namespace stack_using_queue + * @brief Functions for the [Stack Using Queue](https://www.studytonight.com/data-structures/stack-using-queue) implementation + */ +namespace stack_using_queue { + /** + * @brief Stack Class implementation for basic methods of Stack Data Structure. + */ + struct Stack + { + std::queue main_q; ///< stores the current state of the stack + std::queue auxiliary_q; ///< used to carry out intermediate operations to implement stack + uint32_t current_size = 0; ///< stores the current size of the stack + + /** + * Returns the top most element of the stack + * @returns top element of the queue + */ + int top() + { + return main_q.front(); + } + + /** + * @brief Inserts an element to the top of the stack. + * @param val the element that will be inserted into the stack + * @returns void + */ + void push(int val) + { + auxiliary_q.push(val); + while(!main_q.empty()) + { + auxiliary_q.push(main_q.front()); + main_q.pop(); + } + swap(main_q, auxiliary_q); + current_size++; + } + + /** + * @brief Removes the topmost element from the stack + * @returns void + */ + void pop() + { + if(main_q.empty()) { + return; + } + main_q.pop(); + current_size--; + } + + /** + * @brief Utility function to return the current size of the stack + * @returns current size of stack + */ + int size() + { + return current_size; + } + }; +} // namespace stack_using_queue +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + data_structures::stack_using_queue::Stack s; + s.push(1); /// insert an element into the stack + s.push(2); /// insert an element into the stack + s.push(3); /// insert an element into the stack + + assert(s.size()==3); /// size should be 3 + + assert(s.top()==3); /// topmost element in the stack should be 3 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==2); /// topmost element in the stack should now be 2 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==1); + + s.push(5); /// insert an element into the stack + assert(s.top()==5); /// topmost element in the stack should now be 5 + + s.pop(); /// remove the topmost element from the stack + assert(s.top()==1); /// topmost element in the stack should now be 1 + + assert(s.size()==1); /// size should be 1 +} + +/** + * @brief Main function + * Creates a stack and pushed some value into it. + * Through a series of push and pop functions on stack, + * it demostrates the functionality of the custom stack + * declared above. + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} From 61cbc630c3f0249da36dbede88b8212594f0e20d Mon Sep 17 00:00:00 2001 From: Soham Roy <72430659+sohamroy19@users.noreply.github.com> Date: Mon, 18 Oct 2021 20:38:42 +0530 Subject: [PATCH 12/15] fix: max length of arrays and coding style (#1614) * Fixed array max length and coding style Max length of arrays was previously an absurdly high integer, instead implemented a numerical upper bound using log2 (max depth of seg tree being logn). Removed `using namespace std;` and `typedef long long ll;` and other competitive coding practices. Added input prompts. * Fixed remaining clang-tidy warnings * Replaced reference parameters with const & or * * Self-tests and documentation * Improved documentation * Added author names Co-authored-by: David Leal --- range_queries/segtree.cpp | 243 ++++++++++++++++++++++++++++++-------- 1 file changed, 191 insertions(+), 52 deletions(-) diff --git a/range_queries/segtree.cpp b/range_queries/segtree.cpp index 602b3fd95..bc03b5428 100644 --- a/range_queries/segtree.cpp +++ b/range_queries/segtree.cpp @@ -1,79 +1,218 @@ -//#include -#incldue < iostream > -#define MAX 4000000 -using namespace std; -typedef long long ll; -void ConsTree(ll arr[], ll segtree[], ll low, ll high, ll pos) { +/** + * @file + * @brief Implementation of [Segment Tree] + * (https://en.wikipedia.org/wiki/Segment_tree) data structure + * + * @details + * A segment tree, also known as a statistic tree, is a tree data structure used + * for storing information about intervals, or segments. Its classical version + * allows querying which of the stored segments contain a given point, but our + * modification allows us to perform (query) any binary operation on any range + * in the array in O(logN) time. Here, we have used addition (+). + * For range updates, we have used lazy propagation. + * + * * Space Complexity : O(NlogN) \n + * * Build Time Complexity : O(NlogN) \n + * * Query Time Complexity : O(logN) \n + * + * @author [Madhav Gaba](https://github.com/madhavgaba) + * @author [Soham Roy](https://github.com/sohamroy19) + */ + +#include /// for assert +#include /// for log2 +#include /// for IO operations +#include /// for std::vector + +/** + * @brief Constructs the initial segment tree + * + * @param arr input to construct the tree out of + * @param segtree the segment tree + * @param low inclusive lowest index of arr to begin at + * @param high inclusive highest index of arr to end at + * @param pos index of segtree to fill (eg. root node) + * @returns void + */ +void ConsTree(const std::vector &arr, std::vector *segtree, + uint64_t low, uint64_t high, uint64_t pos) { if (low == high) { - segtree[pos] = arr[low]; + (*segtree)[pos] = arr[low]; return; } - ll mid = (low + high) / 2; + + uint64_t mid = (low + high) / 2; ConsTree(arr, segtree, low, mid, 2 * pos + 1); ConsTree(arr, segtree, mid + 1, high, 2 * pos + 2); - segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2]; + (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2]; } -ll query(ll segtree[], ll lazy[], ll qlow, ll qhigh, ll low, ll high, ll pos) { - if (low > high) + +/** + * @brief Returns the sum of all elements in a range + * + * @param segtree the segment tree + * @param lazy for lazy propagation + * @param qlow lower index of the required query + * @param qhigh higher index of the required query + * @param low lower index of query for this function call + * @param high higher index of query for this function call + * @param pos index of segtree to consider (eg. root node) + * @return result of the range query for this function call + */ +int64_t query(std::vector *segtree, std::vector *lazy, + uint64_t qlow, uint64_t qhigh, uint64_t low, uint64_t high, + uint64_t pos) { + if (low > high || qlow > high || low > qhigh) { return 0; - if (qlow > high || qhigh < low) - return 0; - if (lazy[pos] != 0) { - segtree[pos] += lazy[pos] * (high - low + 1); - if (low != high) { - lazy[2 * pos + 1] += lazy[pos]; - lazy[2 * pos + 2] += lazy[pos]; - } - lazy[pos] = 0; } - if (qlow <= low && qhigh >= high) - return segtree[pos]; - ll mid = (low + high) / 2; + + if ((*lazy)[pos] != 0) { + (*segtree)[pos] += (*lazy)[pos] * (high - low + 1); + + if (low != high) { + (*lazy)[2 * pos + 1] += (*lazy)[pos]; + (*lazy)[2 * pos + 2] += (*lazy)[pos]; + } + (*lazy)[pos] = 0; + } + + if (qlow <= low && qhigh >= high) { + return (*segtree)[pos]; + } + + uint64_t mid = (low + high) / 2; + return query(segtree, lazy, qlow, qhigh, low, mid, 2 * pos + 1) + query(segtree, lazy, qlow, qhigh, mid + 1, high, 2 * pos + 2); } -void update(ll segtree[], ll lazy[], ll start, ll end, ll delta, ll low, - ll high, ll pos) { - if (low > high) + +/** + * @brief Updates a range of the segment tree + * + * @param segtree the segment tree + * @param lazy for lazy propagation + * @param start lower index of the required query + * @param end higher index of the required query + * @param delta integer to add to each element of the range + * @param low lower index of query for this function call + * @param high higher index of query for this function call + * @param pos index of segtree to consider (eg. root node) + * @returns void + */ +void update(std::vector *segtree, std::vector *lazy, + int64_t start, int64_t end, int64_t delta, uint64_t low, + uint64_t high, uint64_t pos) { + if (low > high) { return; - if (lazy[pos] != 0) { - segtree[pos] += lazy[pos] * (high - low + 1); - if (low != high) { - lazy[2 * pos + 1] += lazy[pos]; - lazy[2 * pos + 2] += lazy[pos]; - } - lazy[pos] = 0; } - if (start > high || end < low) + + if ((*lazy)[pos] != 0) { + (*segtree)[pos] += (*lazy)[pos] * (high - low + 1); + + if (low != high) { + (*lazy)[2 * pos + 1] += (*lazy)[pos]; + (*lazy)[2 * pos + 2] += (*lazy)[pos]; + } + (*lazy)[pos] = 0; + } + + if (start > high || end < low) { return; + } + if (start <= low && end >= high) { - segtree[pos] += delta * (high - low + 1); + (*segtree)[pos] += delta * (high - low + 1); + if (low != high) { - lazy[2 * pos + 1] += delta; - lazy[2 * pos + 2] += delta; + (*lazy)[2 * pos + 1] += delta; + (*lazy)[2 * pos + 2] += delta; } + return; } - ll mid = (low + high) / 2; + + uint64_t mid = (low + high) / 2; + update(segtree, lazy, start, end, delta, low, mid, 2 * pos + 1); update(segtree, lazy, start, end, delta, mid + 1, high, 2 * pos + 2); - segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2]; + (*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2]; } + +/** + * @brief Self-test implementation + * + * @returns void + */ +static void test() { + int64_t max = static_cast(2 * pow(2, ceil(log2(7))) - 1); + assert(max == 15); + + std::vector arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max); + ConsTree(arr, &segtree, 0, 7 - 1, 0); + + assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 3 + 4 + 5 + 6); + + update(&segtree, &lazy, 2, 4, 1, 0, 7 - 1, 0); + assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 4 + 5 + 6 + 6); + + update(&segtree, &lazy, 0, 6, -2, 0, 7 - 1, 0); + assert(query(&segtree, &lazy, 0, 4, 0, 7 - 1, 0) == -1 + 0 + 2 + 3 + 4); +} + +/** + * @brief Main function + * + * @return 0 on exit + */ int main() { - ll n, c; - scanf("%lld %lld", &n, &c); - ll arr[n] = {0}, p, q, v, choice; - ll segtree[MAX], lazy[MAX] = {0}; - ConsTree(arr, segtree, 0, n - 1, 0); - while (c--) { - scanf("%lld", &choice); - if (choice == 0) { - scanf("%lld %lld %lld", &p, &q, &v); - update(segtree, lazy, p - 1, q - 1, v, 0, n - 1, 0); - } else { - scanf("%lld %lld", &p, &q); - printf("%lld\n", query(segtree, lazy, p - 1, q - 1, 0, n - 1, 0)); + test(); // run self-test implementations + + std::cout << "Enter number of elements: "; + + uint64_t n = 0; + std::cin >> n; + + uint64_t max = static_cast(2 * pow(2, ceil(log2(n))) - 1); + std::vector arr(n), lazy(max), segtree(max); + + int choice = 0; + std::cout << "\nDo you wish to enter each number?:\n" + "1: Yes\n" + "0: No (default initialize them to 0)\n"; + + std::cin >> choice; + if (choice == 1) { + std::cout << "Enter " << n << " numbers:\n"; + for (int i = 1; i <= n; i++) { + std::cout << i << ": "; + std::cin >> arr[i]; } } + + ConsTree(arr, &segtree, 0, n - 1, 0); + + do { + std::cout << "\nMake your choice:\n" + "1: Range update (input)\n" + "2: Range query (output)\n" + "0: Exit\n"; + std::cin >> choice; + + if (choice == 1) { + std::cout << "Enter 1-indexed lower bound, upper bound & value:\n"; + + uint64_t p = 1, q = 1, v = 0; + std::cin >> p >> q >> v; + update(&segtree, &lazy, p - 1, q - 1, v, 0, n - 1, 0); + } else if (choice == 2) { + std::cout << "Enter 1-indexed lower bound & upper bound:\n"; + + uint64_t p = 1, q = 1; + std::cin >> p >> q; + std::cout << query(&segtree, &lazy, p - 1, q - 1, 0, n - 1, 0); + std::cout << "\n"; + } + } while (choice > 0); + return 0; } From 692135b4806b1e9e158638cde0277b6cfa8d1c2e Mon Sep 17 00:00:00 2001 From: Focus <65309793+Focusucof@users.noreply.github.com> Date: Mon, 18 Oct 2021 20:54:00 -0400 Subject: [PATCH 13/15] feat: added atbash cipher (#1760) * feat: add atbash_cipher * [test/fix]: test case expected result * docs: added comments for main and test function * doc: changed brief for test function Co-authored-by: David Leal * updating DIRECTORY.md * doc: fixed test comment Co-authored-by: David Leal * [feat/fix]: made test function static Co-authored-by: David Leal * doc: added author comment Co-authored-by: David Leal * fix: brace style Co-authored-by: David Leal * doc: modified file description and added comments for test function * doc: added comment for #include Co-authored-by: David Leal * doc: added description of the algorithm * Update ciphers/atbash_cipher.cpp Co-authored-by: David Leal * Update ciphers/atbash_cipher.cpp Co-authored-by: David Leal * Update ciphers/atbash_cipher.cpp Co-authored-by: David Leal * Update ciphers/atbash_cipher.cpp Co-authored-by: David Leal * fix: Apply suggestions from code review Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 + ciphers/atbash_cipher.cpp | 83 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 ciphers/atbash_cipher.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 3f55016aa..86e57c9ed 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -19,6 +19,7 @@ * [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp) ## Ciphers + * [Atbash Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/atbash_cipher.cpp) * [Base64 Encoding](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/base64_encoding.cpp) * [Caesar Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/caesar_cipher.cpp) * [Elliptic Curve Key Exchange](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/elliptic_curve_key_exchange.cpp) diff --git a/ciphers/atbash_cipher.cpp b/ciphers/atbash_cipher.cpp new file mode 100644 index 000000000..04c330598 --- /dev/null +++ b/ciphers/atbash_cipher.cpp @@ -0,0 +1,83 @@ +/** + * @file + * @brief [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + * @details The Atbash cipher is a subsitution cipher where the letters of the + * alphabet are in reverse. For example, A is replaced with Z, B is replaced + * with Y, etc. + * + * ### Algorithm + * The algorithm takes a string, and looks up the corresponding reversed letter + * for each letter in the word and replaces it. Spaces are ignored and case is + * preserved. + * + * @author [Focusucof](https://github.com/Focusucof) + */ +#include /// for assert +#include /// for IO operations +#include /// for std::map +#include /// for std::string + +/** \namespace ciphers + * \brief Algorithms for encryption and decryption + */ +namespace ciphers { +/** \namespace atbash + * \brief Functions for the [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + */ +namespace atbash { +std::map atbash_cipher_map = { + {'a', 'z'}, {'b', 'y'}, {'c', 'x'}, {'d', 'w'}, {'e', 'v'}, {'f', 'u'}, + {'g', 't'}, {'h', 's'}, {'i', 'r'}, {'j', 'q'}, {'k', 'p'}, {'l', 'o'}, + {'m', 'n'}, {'n', 'm'}, {'o', 'l'}, {'p', 'k'}, {'q', 'j'}, {'r', 'i'}, + {'s', 'h'}, {'t', 'g'}, {'u', 'f'}, {'v', 'e'}, {'w', 'd'}, {'x', 'c'}, + {'y', 'b'}, {'z', 'a'}, {'A', 'Z'}, {'B', 'Y'}, {'C', 'X'}, {'D', 'W'}, + {'E', 'V'}, {'F', 'U'}, {'G', 'T'}, {'H', 'S'}, {'I', 'R'}, {'J', 'Q'}, + {'K', 'P'}, {'L', 'O'}, {'M', 'N'}, {'N', 'M'}, {'O', 'L'}, {'P', 'K'}, + {'Q', 'J'}, {'R', 'I'}, {'S', 'H'}, {'T', 'G'}, {'U', 'F'}, {'V', 'E'}, + {'W', 'D'}, {'X', 'C'}, {'Y', 'B'}, {'Z', 'A'}, {' ', ' '} + +}; + +/** + * @brief atbash cipher encryption and decryption + * @param text Plaintext to be encrypted + * @returns encoded or decoded string + */ +std::string atbash_cipher(std::string text) { + std::string result; + for (char letter : text) { + result += atbash_cipher_map[letter]; + } + return result; +} + +} // namespace atbash +} // namespace ciphers + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::string text = "Hello World"; + std::string expected = "Svool Dliow"; + std::string encrypted_text = ciphers::atbash::atbash_cipher(text); + std::string decrypted_text = ciphers::atbash::atbash_cipher(encrypted_text); + assert(expected == encrypted_text); + assert(text == decrypted_text); + std::cout << "Original text: " << text << std::endl; + std::cout << ", Expected text: " << expected << std::endl; + std::cout << ", Encrypted text: " << encrypted_text << std::endl; + std::cout << ", Decrypted text: " << decrypted_text << std::endl; + std::cout << "\nAll tests have successfully passed!\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 3406be6d0b2e0e6a7630db8e58bd6f7ffdfe4dc1 Mon Sep 17 00:00:00 2001 From: Alvin Philips Date: Wed, 20 Oct 2021 03:23:07 +0530 Subject: [PATCH 14/15] feat: Add Reverse a Binary Tree implementation (#1767) * 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 Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 1 + .../reverse_binary_tree.cpp | 255 ++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 operations_on_datastructures/reverse_binary_tree.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 86e57c9ed..9a2481213 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -242,6 +242,7 @@ * [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) + * [Reverse Binary Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_binary_tree.cpp) * [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp) * [Trie Multiple Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/trie_multiple_search.cpp) * [Union Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/union_of_2_arrays.cpp) diff --git a/operations_on_datastructures/reverse_binary_tree.cpp b/operations_on_datastructures/reverse_binary_tree.cpp new file mode 100644 index 000000000..46b742efc --- /dev/null +++ b/operations_on_datastructures/reverse_binary_tree.cpp @@ -0,0 +1,255 @@ +/** + * @file + * @brief Implementation for the [Reversing a Binary + * Tree](https://www.geeksforgeeks.org/reverse-tree-path/) recursively + * algorithm. + * @details A binary tree can be reversed by swapping the left and + * right child of a node at each node, starting from the root, and + * cascading below. This solution aims to provide an implementation of + * a recursive reversal of a binary tree. + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// For assert +#include /// For IO operations +#include /// For std::queue +#include /// For std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @namespace reverse_binary_tree + * @brief Functions for the [Reverse a Binary + * Tree](https://www.geeksforgeeks.org/reverse-tree-path/) implementation + */ +namespace reverse_binary_tree { + +/** + * @brief A Node struct that represents a single node in a Binary Tree + */ +struct Node { + int64_t data; ///< The value of the Node + Node* left; ///< The Node's left child + Node* right; ///< The Node's right child + /** + * @brief Creates a new Node with some initial data + */ + explicit Node(int64_t _data) { + data = _data; ///< Set value of Node data + left = nullptr; ///< Initialize left child to NULL + right = nullptr; ///< Initialize right child to NULL + } +}; + +/** + * @brief A Binary Tree class that implements a Binary Search Tree + *(BST) by default. + */ +class BinaryTree { + private: + Node* root; ///< Pointer to root node of Binary Tree + /** + * @brief inserts a node in the Binary Tree, with the behaviouur of + * a Binary Search Tree. + * @details Nodes with smaller values are inserted in the left + * subtree, and Nodes with larger values are inserted into the + * right subtree recursively. Time Complexity: O(log(n)) + * @param data The data/value of the Node to be inserted + * @param pivot A pointer to the root node of the (sub)tree + * @returns Node pointer to the root + */ + Node* insert(int64_t data, Node* pivot) { + if (pivot == nullptr) { + return new Node(data); ///< Create new node + } + if (data <= pivot->data) { + pivot->left = + insert(data, pivot->left); ///< Insert Node to the left + } else { + pivot->right = + insert(data, pivot->right); ///< Insert node to the right + } + return pivot; + } + /** + * @brief Reverses a Binary Tree recursively by swapping the left and + * right subtrees and their children. + * @param pivot A reference to the root of the (sub)tree + * @returns Node pointer to root node + */ + Node* reverseBinaryTree(Node* pivot) { + if (pivot == nullptr) { + return pivot; ///< Base case + } + Node* temp = pivot->left; ///< pointer to the left subtree + pivot->left = reverseBinaryTree(pivot->right); ///< Swap + pivot->right = reverseBinaryTree(temp); ///< Swap + return pivot; + } + + public: + /** + * @brief Creates a BinaryTree with a root pointing to NULL. + */ + BinaryTree() { root = nullptr; } + /** + * @brief Creates a BinaryTree with a root with an initial value. + */ + explicit BinaryTree(int64_t data) { root = new Node(data); } + /** + * @brief Adds a new Node to the Binary Tree + */ + void add(int64_t data) { root = insert(data, root); } + /** + * Reverses the Binary Tree + */ + void reverse() { root = reverseBinaryTree(root); } + /** + * @brief Level order traversal of a tree consists of visiting its + * elements, top to bottom, left to right. This function performs + * level order traversal and returns the node datas as a vector. + * @details The function uses a queue to append and remove elements + * as they are visited, and then adds their children, if any. This + * ensures that the elements are visited layer-by-layer, starting + * from the root of the Tree. + * @returns vector of nodes of the tree. + */ + std::vector get_level_order() { + std::vector data; ///< Result vector of int + if (root == nullptr) { + return data; ///< Return empty vector if root is Invalid + } + std::queue nodes; ///< Queue of the nodes in the tree + nodes.push(root); ///< Insert root into the queue + while (!nodes.empty()) { + Node* temp = nodes.front(); ///< Copy the first element + data.push_back(temp->data); ///< Add the element to the data + nodes.pop(); ///< Remove element + if (temp->left != nullptr) { + nodes.push(temp->left); ///< Insert left node + } + if (temp->right != nullptr) { + nodes.push(temp->right); ///< Insert right node + } + } /// Add nodes while Tree is not empty + return data; + } + /** + * @brief Prints all of the elements in the tree to stdout + * level-by-level, using the get_level_order() function. + * @returns void + */ + void print() { + for (int i : get_level_order()) { + std::cout << i << " "; /// Print each element in the tree + } + std::cout << "\n"; /// Print newline + } +}; + +} // namespace reverse_binary_tree +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check Reversal of Binary Tree. + */ +namespace tests { +using operations_on_datastructures::reverse_binary_tree:: + BinaryTree; ///< Use the BinaryTree +/** + * @brief A Test to check an edge case (single element reversal) + */ +void test1() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::cout << "TEST CASE 1\n"; + std::cout << "Initializing tree with a single element (5)\n"; + bst.add(5); + pre_reversal = bst.get_level_order(); + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(pre_reversal.size() == + post_reversal.size()); ///< Check for equal sizes + assert(pre_reversal.size() == + 1); ///< Ensure that there is only one element + assert(pre_reversal[0] == + post_reversal[0]); ///< Check if both elements are same + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an edge case (NULL root element) + */ +void test2() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::cout << "TEST CASE 2\n"; + std::cout << "Creating empty tree (root points to NULL)\n"; + pre_reversal = bst.get_level_order(); + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(pre_reversal.size() == + post_reversal.size()); ///< Check for equal sizes + assert(pre_reversal.size() == + 0); ///< Ensure that there is only one element + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct reversal of a Binary Tree + */ +void test3() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::vector pre_res = {4, 3, 6, 2, 5, 7, 1}; + std::vector post_res = {4, 6, 3, 7, 5, 2, 1}; + std::cout << "TEST CASE 3\n"; + std::cout << "Creating tree with elements (4, 6, 3, 2, 5, 7, 1)\n"; + bst.add(4); + bst.add(6); + bst.add(3); + bst.add(2); + bst.add(5); + bst.add(7); + bst.add(1); + pre_reversal = bst.get_level_order(); + assert(pre_reversal == pre_res); ///< Check for equality + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(post_reversal == post_res); ///< Check for equality + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of the Tree Reversal + */ +static void test() { + tests::test1(); ///< Single element test + tests::test2(); ///< No element test + tests::test3(); ///< Correct reversal test +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From 8ae862730f2efc15cc47e6b75c03064412a99285 Mon Sep 17 00:00:00 2001 From: Alvin Philips Date: Thu, 21 Oct 2021 01:43:35 +0530 Subject: [PATCH 15/15] fix: Missing period in the `CONTRIBUTING.md` file (#1772) Missing period at the end of sentence --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2ff8cb72c..09434e085 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ You can add new algorithms or data structures which are **not present in the rep - Please use the directory structure of the repository. - 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 +- 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.