Merge branch 'master' into aminos

This commit is contained in:
ERR !
2021-08-27 03:21:24 +05:30
committed by GitHub
9 changed files with 943 additions and 14 deletions

View File

@@ -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)

View File

@@ -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.

View File

@@ -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 <cassert> /// for assert
#include <iostream> /// for IO operations
#include <vector> /// 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<std::vector<int64_t>> dpTable(1000, std::vector<int64_t>(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;
}

View File

@@ -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 <cassert> /// for assert
#include <iostream> /// 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<uint64_t>(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;
}

View File

@@ -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 <cassert> /// for assert
#include <cstring> /// for string
#include <iostream> /// for IO operations
#include <vector> /// 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;
}

View File

@@ -24,7 +24,7 @@ class hash_chain {
};
std::vector<std::shared_ptr<Node>> 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<Node> 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();

123
math/n_bonacci.cpp Normal file
View File

@@ -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 <algorithm> /// for std::is_equal, std::swap
#include <cassert> /// for assert
#include <iostream> /// for IO operations
#include <vector> /// 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<uint64_t> N_bonacci(const uint64_t &n, const uint64_t &m) {
std::vector<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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;
}

268
others/lru_cache.cpp Normal file
View File

@@ -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 <cassert> /// for assert
#include <iostream> /// for IO Operations
#include <list> /// for std::list
#include <unordered_map> /// 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<uint64_t> cache; ///< Cache linked list (using the STL)
std::unordered_map<uint64_t, std::list<uint64_t>::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 <typename T>
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;
}

109
sorting/dnf_sort.cpp Normal file
View File

@@ -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 <algorithm> /// for std::is_sorted
#include <cassert> /// for assert
#include <iostream> /// for std::swap and io operations
#include <vector> /// 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 <typename T>
std::vector<T> dnfSort(const std::vector<T> &in_arr) {
std::vector<T> 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<uint64_t> array1 = {0, 1, 1, 2};
std::cout << "Test 1... ";
std::vector<uint64_t> 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<uint64_t> array2 = {1, 0, 0, 1, 1, 0, 2, 1};
std::cout << "Test 2... ";
std::vector<uint64_t> 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<uint64_t> array3 = {1, 1, 0, 0, 1, 2, 2, 0, 2, 1};
std::cout << "Test 3... ";
std::vector<uint64_t> 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<uint64_t> array4 = {2, 2, 2, 0, 0, 1, 1};
std::cout << "Test 4... ";
std::vector<uint64_t> 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;
}