diff --git a/DIRECTORY.md b/DIRECTORY.md index 3a830d71a..58d45455a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -11,9 +11,11 @@ * [Subarray Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subarray_sum.cpp) * [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) + * [Wildcard Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/wildcard_matching.cpp) ## Bit Manipulation * [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/count_of_set_bits.cpp) + * [Count Of Trailing Ciphers In Factorial N](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp) * [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp) ## Ciphers @@ -64,6 +66,9 @@ * [Trie Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/trie_tree.cpp) * [Trie Using Hashmap](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/trie_using_hashmap.cpp) +## Divide And Conquer + * [Karatsuba Algorithm For Fast Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp) + ## Dynamic Programming * [0 1 Knapsack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/0_1_knapsack.cpp) * [Abbreviation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/abbreviation.cpp) @@ -181,6 +186,7 @@ * [Modular Division](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_division.cpp) * [Modular Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_exponentiation.cpp) * [Modular Inverse Fermat Little Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_inverse_fermat_little_theorem.cpp) + * [N Bonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/n_bonacci.cpp) * [N Choose R](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/n_choose_r.cpp) * [Ncr Modulo P](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/ncr_modulo_p.cpp) * [Number Of Positive Divisors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/number_of_positive_divisors.cpp) @@ -237,6 +243,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) + * [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) * [Paranthesis Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/paranthesis_matching.cpp) @@ -292,6 +299,7 @@ * [Counting Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/counting_sort.cpp) * [Counting Sort String](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/counting_sort_string.cpp) * [Cycle Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/cycle_sort.cpp) + * [Dnf Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/dnf_sort.cpp) * [Gnome Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/gnome_sort.cpp) * [Heap Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/heap_sort.cpp) * [Insertion Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/insertion_sort.cpp) diff --git a/README.md b/README.md index c04838474..5766d0f83 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ ## Overview -The repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). The algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. +The repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. ## Features * The repository provides implementations of various algorithms in one of the most fundamental general purpose languages - [C++](https://en.wikipedia.org/wiki/C%2B%2B). * Well documented source code with detailed explanations provide a valuable resource for educators and students alike. -* Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus the fundamentals of the algorithms can be studied in much depth. +* Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus, the fundamentals of the algorithms can be studied in much depth. * Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems viz., Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. * Strict adherence to [C++11](https://en.wikipedia.org/wiki/C%2B%2B11) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, etc. with little to no changes. * Self-checks within programs ensure correct implementations with confidence. diff --git a/backtracking/wildcard_matching.cpp b/backtracking/wildcard_matching.cpp new file mode 100644 index 000000000..d9163a41b --- /dev/null +++ b/backtracking/wildcard_matching.cpp @@ -0,0 +1,155 @@ +/** + * @file + * @brief Implementation of the [Wildcard + * Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem. + * @details + * Given a matching string and a pattern, implement wildcard pattern + * matching with support for `?` and `*`. `?` matches any single character. + * `*` matches any sequence of characters (including the empty sequence). + * The matching should cover the entire matching string (not partial). The task + * is to determine if the pattern matches with the matching string + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace wildcard_matching + * @brief Functions for the [Wildcard + * Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem. + */ +namespace wildcard_matching { +/** + * @brief The main function implements if pattern can be matched with given + * string + * @param s is the given matching string + * @param p is the given pattern + * @param pos1 is the starting index + * @param pos2 is the last index + * @returns 1 if pattern matches with matching string otherwise 0 + */ +std::vector> dpTable(1000, std::vector(1000, -1)); +bool wildcard_matching(std::string s, std::string p, uint32_t pos1, + uint32_t pos2) { + uint32_t n = s.length(); + uint32_t m = p.length(); + // matching is successfull if both strings are done + if (pos1 == n && pos2 == m) { + return true; + } + + // matching is unsuccessfull if pattern is not finished but matching string + // is + if (pos1 != n && pos2 == m) { + return false; + } + + // all the remaining characters of patterns must be * inorder to match with + // finished string + if (pos1 == n && pos2 != m) { + while (pos2 < m && p[pos2] == '*') { + pos2++; + } + + return pos2 == m; + } + + // if already calculted for these positions + if (dpTable[pos1][pos2] != -1) { + return dpTable[pos1][pos2]; + } + + // if the characters are same just go ahead in both the string + if (s[pos1] == p[pos2]) { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1 + 1, pos2 + 1); + } + + else { + // can only single character + if (p[pos2] == '?') { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1 + 1, pos2 + 1); + } + // have choice either to match one or more charcters + else if (p[pos2] == '*') { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1, pos2 + 1) || + wildcard_matching(s, p, pos1 + 1, pos2); + } + // not possible to match + else { + return dpTable[pos1][pos2] = 0; + } + } +} + +} // namespace wildcard_matching +} // namespace backtracking + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::cout << "1st test "; + std::string matching1 = "baaabab"; + std::string pattern1 = "*****ba*****ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching1, + pattern1, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 2nd test + std::cout << "2nd test "; + std::string matching2 = "baaabab"; + std::string pattern2 = "ba*****ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching2, + pattern2, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 3rd test + std::cout << "3rd test "; + std::string matching3 = "baaabab"; + std::string pattern3 = "ba*ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching3, + pattern3, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 4th test + std::cout << "4th test "; + std::string matching4 = "baaabab"; + std::string pattern4 = "a*ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching4, + pattern4, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 5th test + std::cout << "5th test "; + std::string matching5 = "baaabab"; + std::string pattern5 = "aa?ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching5, + pattern5, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp b/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp new file mode 100644 index 000000000..aa2ceb3dd --- /dev/null +++ b/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp @@ -0,0 +1,98 @@ +/** + * @file + * @brief [Count the number of + * ciphers](https://www.tutorialspoint.com/count-trailing-zeros-in-factorial-of-a-number-in-cplusplus) in `n!` implementation + * @details + * Given an integer number as input. The goal is to find the number of trailing + zeroes in the factorial calculated for + * that number. A factorial of a number N is a product of all numbers in the + range [1, N]. + + * We know that we get a trailing zero only if the number is multiple of 10 or + has a factor pair (2,5). In all factorials of + * any number greater than 5, we have many 2s more than 5s in the prime + factorization of that number. Dividing a + * number by powers of 5 will give us the count of 5s in its factors. So, the + number of 5s will tell us the number of trailing zeroes. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations + +/** + * @namespace bit_manipulation + * @brief Bit manipulation algorithms + */ +namespace bit_manipulation { +/** + * @namespace count_of_trailing_ciphers_in_factorial_n + * @brief Functions for the [Count the number of + * ciphers](https://www.tutorialspoint.com/count-trailing-zeros-in-factorial-of-a-number-in-cplusplus) + * in `n!` implementation + */ +namespace count_of_trailing_ciphers_in_factorial_n { +/** + * @brief Function to count the number of the trailing ciphers + * @param n number for which `n!` ciphers are returned + * @return count, Number of ciphers in `n!`. + */ +uint64_t numberOfCiphersInFactorialN(uint64_t n) { + // count is to store the number of 5's in factorial(n) + uint64_t count = 0; + + // Keep dividing n by powers of + // 5 and update count + for (uint64_t i = 5; n / i >= 1; i *= 5) { + count += static_cast(n) / i; + } + + return count; +} +} // namespace count_of_trailing_ciphers_in_factorial_n +} // namespace bit_manipulation + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::cout << "1st test "; + assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n:: + numberOfCiphersInFactorialN(395) == 97); + std::cout << "passed" << std::endl; + + // 2nd test + std::cout << "2nd test "; + assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n:: + numberOfCiphersInFactorialN(977) == 242); + std::cout << "passed" << std::endl; + + // 3rd test + std::cout << "3rd test "; + assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n:: + numberOfCiphersInFactorialN(871) == 215); + std::cout << "passed" << std::endl; + + // 4th test + std::cout << "4th test "; + assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n:: + numberOfCiphersInFactorialN(239) == 57); + std::cout << "passed" << std::endl; + + // 5th test + std::cout << "5th test "; + assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n:: + numberOfCiphersInFactorialN(0) == 0); + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp b/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp new file mode 100644 index 000000000..1782d0a45 --- /dev/null +++ b/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp @@ -0,0 +1,167 @@ +/** + * @file + * @brief Implementation of the [Karatsuba algorithm for fast + * multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) + * @details + * Given two strings in binary notation we want to multiply them and return the + * value Simple approach is to multiply bits one by one which will give the time + * complexity of around O(n^2). To make it more efficient we will be using + * Karatsuba' algorithm to find the product which will solve the problem + * O(nlogn) of time. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for string +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace divide_and_conquer + * @brief Divide and Conquer algorithms + */ +namespace divide_and_conquer { +/** + * @namespace karatsuba_algorithm + * @brief Functions for the [Karatsuba algorithm for fast + * multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) + */ +namespace karatsuba_algorithm { +/** + * @brief Helper function for the main function, that implements Karatsuba's + * algorithm for fast multiplication + * @param first the input string 1 + * @param second the input string 2 + * @returns the concatenated string + */ +std::string addStrings(std::string first, std::string second) { + std::string result; // To store the resulting sum bits + + int64_t len1 = first.size(); + int64_t len2 = second.size(); + int64_t length = std::max(len1, len2); + std::string zero = "0"; + if (len1 < len2) // make the string lengths equal + { + for (int64_t i = 0; i < len2 - len1; i++) { + zero += first; + first = zero; + } + } else if (len1 > len2) { + zero = "0"; + for (int64_t i = 0; i < len1 - len2; i++) { + zero += second; + second = zero; + } + } + int64_t carry = 0; + for (int64_t i = length - 1; i >= 0; i--) { + int64_t firstBit = first.at(i) - '0'; + int64_t secondBit = second.at(i) - '0'; + + int64_t sum = (firstBit ^ secondBit ^ carry) + '0'; // sum of 3 bits + std::string temp; + temp = std::to_string(sum); + temp += result; + result = temp; + + carry = (firstBit & secondBit) | (secondBit & carry) | + (firstBit & carry); // sum of 3 bits + } + + if (carry) { + result = '1' + result; // adding 1 incase of overflow + } + return result; +} +/** + * @brief The main function implements Karatsuba's algorithm for fast + * multiplication + * @param str1 the input string 1 + * @param str2 the input string 2 + * @returns the multiplicative number value + */ +int64_t karatsuba_algorithm(std::string str1, std::string str2) { + int64_t len1 = str1.size(); + int64_t len2 = str2.size(); + int64_t n = std::max(len1, len2); + std::string zero = "0"; + if (len1 < len2) { + for (int64_t i = 0; i < len2 - len1; i++) { + zero += str1; + str1 = zero; + } + } else if (len1 > len2) { + zero = "0"; + for (int64_t i = 0; i < len1 - len2; i++) { + zero += str2; + str2 = zero; + } + } + if (n == 0) { + return 0; + } + if (n == 1) { + return (str1[0] - '0') * (str2[0] - '0'); + } + int64_t fh = n / 2; // first half of string + int64_t sh = (n - fh); // second half of string + + std::string Xl = str1.substr(0, fh); // first half of first string + std::string Xr = str1.substr(fh, sh); // second half of first string + + std::string Yl = str2.substr(0, fh); // first half of second string + std::string Yr = str2.substr(fh, sh); // second half of second string + + // Calculating the three products of inputs of size n/2 recursively + int64_t product1 = karatsuba_algorithm(Xl, Yl); + int64_t product2 = karatsuba_algorithm(Xr, Yr); + int64_t product3 = karatsuba_algorithm( + divide_and_conquer::karatsuba_algorithm::addStrings(Xl, Xr), + divide_and_conquer::karatsuba_algorithm::addStrings(Yl, Yr)); + + return product1 * (1 << (2 * sh)) + + (product3 - product1 - product2) * (1 << sh) + + product2; // combining the three products to get the final result. +} +} // namespace karatsuba_algorithm +} // namespace divide_and_conquer + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::string s11 = "1"; + std::string s12 = "1010"; + std::cout << "1st test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s11, s12) == 10); // here the multiplication is 10 + std::cout << "passed" << std::endl; + + // 2nd test + std::string s21 = "11"; + std::string s22 = "1010"; + std::cout << "2nd test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s21, s22) == 30); // here the multiplication is 30 + std::cout << "passed" << std::endl; + + // 3rd test + std::string s31 = "110"; + std::string s32 = "1010"; + std::cout << "3rd test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s31, s32) == 60); // here the multiplication is 60 + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/hashing/chaining.cpp b/hashing/chaining.cpp index ae902c90e..9c5a2a076 100644 --- a/hashing/chaining.cpp +++ b/hashing/chaining.cpp @@ -24,7 +24,7 @@ class hash_chain { }; std::vector> head; ///< array of nodes - int _mod; ///< modulus of the class + int _mod; ///< modulus of the class public: /** @@ -67,10 +67,10 @@ class hash_chain { if (!head[i]) { std::cout << "Key " << i << " is empty" << std::endl; } else { - std::cout << "Key " << i << " has values = "; + std::cout << "Key " << i << " has values = " << std::endl; temp = head[i]; while (temp->next) { - std::cout << temp->data << " "; + std::cout << temp->data << " " << std::endl; temp = temp->next; } std::cout << temp->data; @@ -102,7 +102,7 @@ class hash_chain { std::shared_ptr temp = head[h]; if (!head[h]) { // index does not exist! - std::cout << "Element not found"; + std::cout << "Element not found" << std::endl; return false; } @@ -110,19 +110,19 @@ class hash_chain { while (temp->data != x && temp->next) temp = temp->next; if (temp->next) { - std::cout << "Element found"; + std::cout << "Element found" << std::endl; return true; } // implicit else condition // i.e., temp->next == nullptr if (temp->data == x) { - std::cout << "Element found"; + std::cout << "Element found" << std::endl; return true; } // further implicit else condition - std::cout << "Element not found"; + std::cout << "Element not found" << std::endl; return false; } }; @@ -132,7 +132,7 @@ class hash_chain { */ int main() { int c = 0, x = 0, mod = 0, h = 0; - std::cout << "Enter the size of Hash Table. = "; + std::cout << "Enter the size of Hash Table. = " << std::endl; std::cin >> mod; hash_chain mychain(mod); @@ -149,22 +149,23 @@ int main() { std::cin >> c; switch (c) { case 1: - std::cout << "Enter element to add = "; + std::cout << "Enter element to add = " << std::endl; std::cin >> x; h = mychain.hash(x); h = std::abs(h); mychain.add(x, h); break; case 2: - std::cout << "Enter element to search = "; + std::cout << "Enter element to search = " << std::endl; std::cin >> x; h = mychain.hash(x); mychain.find(x, h); break; case 3: - std::cout << "Enter element to generate hash = "; + std::cout << "Enter element to generate hash = " << std::endl; std::cin >> x; - std::cout << "Hash of " << x << " is = " << mychain.hash(x); + std::cout << "Hash of " << x << " is = " << mychain.hash(x) + << std::endl; break; case 4: mychain.display(); diff --git a/math/n_bonacci.cpp b/math/n_bonacci.cpp new file mode 100644 index 000000000..845cad734 --- /dev/null +++ b/math/n_bonacci.cpp @@ -0,0 +1,123 @@ +/** + * @file + * @brief Implementation of the + * [N-bonacci](http://oeis.org/wiki/N-bonacci_numbers) series + * + * @details + * In general, in N-bonacci sequence, + * we generate sum of preceding N numbers from the next term. + * + * For example, a 3-bonacci sequence is the following: + * 0, 0, 1, 1, 2, 4, 7, 13, 24, 44, 81 + * In this code we take N and M as input where M is the number of terms + * to be printed of the N-bonacci series + * + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for std::is_equal, std::swap +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace math + * @brief Mathematical algorithms + */ +namespace math { +/** + * @namespace n_bonacci + * @brief Functions for the [N-bonacci](http://oeis.org/wiki/N-bonacci_numbers) + * implementation + */ +namespace n_bonacci { +/** + * @brief Finds the N-Bonacci series for the `n` parameter value and `m` + * parameter terms + * @param n is in the N-Bonacci series + * @param m is the number of terms in the N-Bonacci sequence + * @returns the n-bonacci sequence as vector array + */ +std::vector N_bonacci(const uint64_t &n, const uint64_t &m) { + std::vector a(m, 0); // we create an empty array of size m + + a[n - 1] = 1; /// we initialise the (n-1)th term as 1 which is the sum of + /// preceding N zeros + a[n] = 1; /// similarily the sum of preceding N zeros and the (N+1)th 1 is + /// also 1 + for (uint64_t i = n + 1; i < m; i++) { + // this is an optimized solution that works in O(M) time and takes O(M) + // extra space here we use the concept of the sliding window the current + // term can be computed using the given formula + a[i] = 2 * a[i - 1] - a[i - 1 - n]; + } + return a; +} +} // namespace n_bonacci +} // namespace math + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // n = 1 m = 1 return [1, 1] + std::cout << "1st test"; + std::vector arr1 = math::n_bonacci::N_bonacci( + 1, 1); // first input is the param n and second one is the param m for + // N-bonacci func + std::vector output_array1 = { + 1, 1}; // It is the expected output series of length m + assert(std::equal(std::begin(arr1), std::end(arr1), + std::begin(output_array1))); + std::cout << "passed" << std::endl; + + // n = 5 m = 15 return [0, 0, 0, 0, 1, 1, 2, 4, 8, 16, 31, 61, 120, 236, + // 464] + std::cout << "2nd test"; + std::vector arr2 = math::n_bonacci::N_bonacci( + 5, 15); // first input is the param n and second one is the param m for + // N-bonacci func + std::vector output_array2 = { + 0, 0, 0, 0, 1, 1, 2, 4, + 8, 16, 31, 61, 120, 236, 464}; // It is the expected output series of + // length m + assert(std::equal(std::begin(arr2), std::end(arr2), + std::begin(output_array2))); + std::cout << "passed" << std::endl; + + // n = 6 m = 17 return [0, 0, 0, 0, 0, 1, 1, 2, 4, 8, 16, 32, 63, 125, 248, + // 492, 976] + std::cout << "3rd test"; + std::vector arr3 = math::n_bonacci::N_bonacci( + 6, 17); // first input is the param n and second one is the param m for + // N-bonacci func + std::vector output_array3 = { + 0, 0, 0, 0, 0, 1, 1, 2, 4, + 8, 16, 32, 63, 125, 248, 492, 976}; // It is the expected output series + // of length m + assert(std::equal(std::begin(arr3), std::end(arr3), + std::begin(output_array3))); + std::cout << "passed" << std::endl; + + // n = 56 m = 15 return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + std::cout << "4th test"; + std::vector arr4 = math::n_bonacci::N_bonacci( + 56, 15); // first input is the param n and second one is the param m + // for N-bonacci func + std::vector output_array4 = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; // It is the expected output series of length m + assert(std::equal(std::begin(arr4), std::end(arr4), + std::begin(output_array4))); + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/others/lru_cache.cpp b/others/lru_cache.cpp new file mode 100644 index 000000000..f9cd3caec --- /dev/null +++ b/others/lru_cache.cpp @@ -0,0 +1,268 @@ +/** + * @file + * @brief An implementation of + * [LRU + * Cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)). + * Lru is a part of cache algorithms (also frequently called cache replacement + * algorithms or cache replacement policies). + * + * ### Logic + * * Discards the least recently used items first. + * * This algorithm requires keeping track of what was used when, which is + * expensive if one wants to make sure the algorithm always discards the least + * recently used item. + * * General implementations of this technique require keeping "age bits" + * for cache-lines and track the "Least Recently Used" cache-line based on + * age-bits. + * * In such an implementation, every time a cache-line is used, the age of + * all other cache-lines changes + * + * ### Algorithm explanation + * For a cache of page frame x: + * * Check if the page is present in cache. + * * If not present, then check is the cache is full or not: + * * If the cache is full, REMOVE the last element from the cache. + * * If the element is present in cache, then shift that element to + * first position in cache from its original position. + * * This way you can keep the least recently used elements in the + * last and most recently used in front of the cache. + * + * Every time a requested page is not found in cache, that is a miss or page + * fault, and if the page is present in cache, then its a hit. + * + * ## Data Structure used + * * In the algorithm below we used two different data structure, one is linked + * list and other one is a hash map + * * The linked list is used to contain the pages and the hash map contains the + * pages and their address. + * * Every time a new page is requested, we first check in the hash map if the + * page is present or not. + * * If not present, and the cache is full, we simply delete the last entry in + * the cache. + * * If present, we shift that page from its current location to beginning of + * the cache and update the address in hash map for that page. + * + * @author [Nitin Sharma](https://github.com/foo290) + * */ + +#include /// for assert +#include /// for IO Operations +#include /// for std::list +#include /// for std::unordered_map + +/** + * @namespace others + * @brief Other algorithms + */ +namespace others { +/** + * @namespace lru_cache + * @brief Implementation of the [LRU caching + * algorithm](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)) + */ +namespace lru_cache { +/** + * @brief LRU cache class + */ +class LRUCache { + uint64_t pageFrame; ///< Page frame, or total size of the cache. + std::list cache; ///< Cache linked list (using the STL) + std::unordered_map::iterator> + pageMap; ///< Hash map containing pages and their addresses + + uint64_t hits = + 0; ///< Total number of hits, or total number of times a page + ///< was found in cache. + uint64_t pageFault = 0; ///< Total number of miss/page fault, or total + ///< number of times a page was not found in cache + + public: + /** + * @brief Constructor, Initialize thee LRU class with page frame. + * @param pf Page frame or total size of cache. + * */ + explicit LRUCache(uint64_t pf) { pageFrame = pf; } + + /** + * @brief Refer to a page, or request a page from memory. + * @param page The page that you are referring to. + * @returns void + * */ + void refer(uint64_t page) { + // If the page requested not in cache. + if (pageMap.find(page) == pageMap.end()) { + pageFault++; ///< Increase the page fault by one. + + // Check if the cache is full + if (cache.size() == pageFrame) { + // delete the last page from cache + uint64_t lastPage = cache.back(); + cache.pop_back(); + pageMap.erase(lastPage); + } + } + // The requested page is in the cache + else { + hits++; + // present in cache, erase from current position to bring in front + cache.erase(pageMap[page]); + } + // Push it in the front of the cache and update the page reference in + // page map. + cache.push_front(page); + pageMap[page] = cache.begin(); + } + + /** + * @brief A function to display the current cache + * @returns Void + * */ + void display() { + for (uint64_t &it : cache) { + std::cout << it << " "; + } + std::cout << std::endl; + } + /** + * @brief A function to get page hits + * @returns int + * */ + uint64_t getHits() const { return hits; } + /** + * @brief A function to get page fault + * @returns int + * */ + uint64_t getPageFault() const { return pageFault; } +}; + +} // namespace lru_cache +} // namespace others + +namespace lru_tests { +/** + * @brief A function to print given message on console. + * @tparam T Type of the given message. + * @returns void + * */ +template +void log(T msg) { + // It's just to avoid writing cout and endl + std::cout << "[TESTS] : ---> " << msg << std::endl; +} + +/** + * @brief A simple test case + * The assert statement will check expected hist and miss to resultant hits and + * miss + * @returns void + * */ +static void test_1() { + uint64_t expected_hits = 2; + uint64_t expected_pageFault = 4; + + log("Running Test-1..."); + + others::lru_cache::LRUCache cache(4); + cache.refer(1); + cache.refer(2); + cache.refer(5); + cache.refer(1); + cache.refer(4); + cache.refer(5); + + log("Checking assert statement..."); + assert(cache.getHits() == expected_hits && + cache.getPageFault() == expected_pageFault); + log("Assert successful!"); + log("Test-1 complete!"); +} + +/** + * @brief A test case contains hits more than cache size + * The assert statement will check expected hist and miss to resultant hits and + * miss + * @returns void + * */ +static void test_2() { + uint64_t expected_hits = 4; + uint64_t expected_pageFault = 2; + + log("Running Test-2..."); + + others::lru_cache::LRUCache cache(4); + cache.refer(1); + cache.refer(1); + cache.refer(1); + cache.refer(1); + cache.refer(1); + cache.refer(5); + + log("Checking assert statement..."); + assert(cache.getHits() == expected_hits && + cache.getPageFault() == expected_pageFault); + log("Assert successful!"); + log("Test-2 complete!"); +} + +/** + * @brief A simple test case + * The assert statement will check expected hist and miss to resultant hits and + * miss + * @returns void + * */ +static void test_3() { + uint64_t expected_hits = 1; + uint64_t expected_pageFault = 5; + + log("Running Test-3..."); + + others::lru_cache::LRUCache cache(4); + cache.refer(1); + cache.refer(2); + cache.refer(3); + cache.refer(4); + cache.refer(5); + cache.refer(5); + + log("Checking assert statement..."); + assert(cache.getHits() == expected_hits && + cache.getPageFault() == expected_pageFault); + log("Assert successful!"); + log("Test-3 complete!"); +} + +/** + * @brief A function to invoke all test cases + * @returns void + * */ +static void run_tests() { + test_1(); + test_2(); + test_3(); + log(""); + log("TESTS COMPLETED!"); +} +} // namespace lru_tests + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + lru_tests::run_tests(); + + // Usage + others::lru_cache::LRUCache cache(4); + cache.refer(1); + cache.refer(2); + cache.refer(3); + cache.refer(4); + cache.refer(5); + cache.refer(5); + + cache.display(); + + std::cout << "Hits: " << cache.getHits() + << " Miss: " << cache.getPageFault() << std::endl; + return 0; +} diff --git a/sorting/dnf_sort.cpp b/sorting/dnf_sort.cpp new file mode 100644 index 000000000..0b13cffbe --- /dev/null +++ b/sorting/dnf_sort.cpp @@ -0,0 +1,109 @@ +/** + * @file + * @brief Implementation of the [DNF + * sort](https://www.geeksforgeeks.org/sort-an-array-of-0s-1s-and-2s/) implementation + * @details + * C++ program to sort an array with 0, 1 and 2 in a single pass(DNF sort). + * Since one traversal of the array is there hence it works in O(n) time + * complexity. + * @author [Sujal Gupta](https://github.com/heysujal) + */ + +#include /// for std::is_sorted +#include /// for assert +#include /// for std::swap and io operations +#include /// for std::vector + +/** + * @namespace sorting + * @breif Sorting algorithms + */ +namespace sorting { +/** + * @namespace dnf_sort + * @brief Functions for the [DNF + * sort](https://en.wikipedia.org/wiki/Dutch_national_flag_problem) implementation + */ +namespace dnf_sort { +/** + * @brief The main function implements DNF sort + * @tparam T type of array + * @param a array to be sorted, + * @param arr_size size of array + * @returns void + */ +template +std::vector dnfSort(const std::vector &in_arr) { + std::vector arr(in_arr); + uint64_t lo = 0; + uint64_t hi = arr.size() - 1; + uint64_t mid = 0; + + // Iterate till all the elements + // are sorted + while (mid <= hi) { + switch (arr[mid]) { + // If the element is 0 + case 0: + std::swap(arr[lo++], arr[mid++]); + break; + + // If the element is 1 . + case 1: + mid++; + break; + + // If the element is 2 + case 2: + std::swap(arr[mid], arr[hi--]); + break; + } + } + return arr; +} +} // namespace dnf_sort +} // namespace sorting + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + // [1, 0, 2, 1] return [0, 1, 1, 2] + std::vector array1 = {0, 1, 1, 2}; + std::cout << "Test 1... "; + std::vector arr1 = sorting::dnf_sort::dnfSort(array1); + assert(std::is_sorted(std::begin(arr1), std::end(arr1))); + std::cout << "passed" << std::endl; + // 2nd test + // [1, 0, 0, 1, 1, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2] + std::vector array2 = {1, 0, 0, 1, 1, 0, 2, 1}; + std::cout << "Test 2... "; + std::vector arr2 = sorting::dnf_sort::dnfSort(array2); + assert(std::is_sorted(std::begin(arr2), std::end(arr2))); + std::cout << "passed" << std::endl; + // 3rd test + // [1, 1, 0, 0, 1, 2, 2, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2, 2, 2] + std::vector array3 = {1, 1, 0, 0, 1, 2, 2, 0, 2, 1}; + std::cout << "Test 3... "; + std::vector arr3 = sorting::dnf_sort::dnfSort(array3); + assert(std::is_sorted(std::begin(arr3), std::end(arr3))); + std::cout << "passed" << std::endl; + // 4th test + // [2, 2, 2, 0, 0, 1, 1] return [0, 0, 1, 1, 2, 2, 2] + std::vector array4 = {2, 2, 2, 0, 0, 1, 1}; + std::cout << "Test 4... "; + std::vector arr4 = sorting::dnf_sort::dnfSort(array4); + assert(std::is_sorted(std::begin(arr4), std::end(arr4))); + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // execute the test + return 0; +}