diff --git a/DIRECTORY.md b/DIRECTORY.md index fa7b669ce..de61aaae2 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 + * [A1Z26 Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/a1z26_cipher.cpp) * [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) @@ -45,6 +46,8 @@ * [Main Cll](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/cll/main_cll.cpp) * [Disjoint Set](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/disjoint_set.cpp) * [Doubly Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/doubly_linked_list.cpp) + * [Dsu Path Compression](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/dsu_path_compression.cpp) + * [Dsu Union Rank](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/dsu_union_rank.cpp) * [Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/linked_list.cpp) * [Linkedlist Implentation Usingarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/linkedlist_implentation_usingarray.cpp) * [List Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/list_array.cpp) @@ -162,6 +165,7 @@ * [Vector Ops](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/machine_learning/vector_ops.hpp) ## Math + * [Area](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/area.cpp) * [Armstrong Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/armstrong_number.cpp) * [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binary_exponent.cpp) * [Binomial Calculate](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/binomial_calculate.cpp) @@ -241,12 +245,12 @@ * [Circular Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_queue_using_array.cpp) * [Get Size Of Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/get_size_of_linked_list.cpp) * [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp) - * [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp) + * [Intersection Of Two Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_two_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) + * [Union Of Two Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/union_of_two_arrays.cpp) ## Others * [Buzz Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/buzz_number.cpp) @@ -335,7 +339,7 @@ * [Radix Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort2.cpp) * [Random Pivot Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/random_pivot_quick_sort.cpp) * [Recursive Bubble Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/recursive_bubble_sort.cpp) - * [Selection Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort.cpp) + * [Selection Sort Iterative](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort_iterative.cpp) * [Selection Sort Recursive](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort_recursive.cpp) * [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort.cpp) * [Shell Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort2.cpp) diff --git a/bit_manipulation/count_of_set_bits.cpp b/bit_manipulation/count_of_set_bits.cpp index 497346a53..f2d802061 100644 --- a/bit_manipulation/count_of_set_bits.cpp +++ b/bit_manipulation/count_of_set_bits.cpp @@ -5,7 +5,8 @@ * integer. * * @details - * We are given an integer number. We need to calculate the number of set bits in it. + * We are given an integer number. We need to calculate the number of set bits + * in it. * * A binary number consists of two digits. They are 0 & 1. Digit 1 is known as * set bit in computer terms. @@ -15,7 +16,7 @@ * @author [Prashant Thakur](https://github.com/prashant-th18) */ #include /// for assert -#include /// for IO operations +#include /// for IO operations /** * @namespace bit_manipulation * @brief Bit manipulation algorithms @@ -33,21 +34,21 @@ namespace count_of_set_bits { * @param n is the number whose set bit will be counted * @returns total number of set-bits in the binary representation of number `n` */ -std::uint64_t countSetBits(std :: int64_t n) { // int64_t is preferred over int so that - // no Overflow can be there. +std::uint64_t countSetBits( + std ::int64_t n) { // int64_t is preferred over int so that + // no Overflow can be there. - int count = 0; // "count" variable is used to count number of set-bits('1') in - // binary representation of number 'n' - while (n != 0) - { + int count = 0; // "count" variable is used to count number of set-bits('1') + // in binary representation of number 'n' + while (n != 0) { ++count; n = (n & (n - 1)); } return count; // Why this algorithm is better than the standard one? // Because this algorithm runs the same number of times as the number of - // set-bits in it. Means if my number is having "3" set bits, then this while loop - // will run only "3" times!! + // set-bits in it. Means if my number is having "3" set bits, then this + // while loop will run only "3" times!! } } // namespace count_of_set_bits } // namespace bit_manipulation diff --git a/ciphers/a1z26_cipher.cpp b/ciphers/a1z26_cipher.cpp new file mode 100644 index 000000000..82a3d3bb4 --- /dev/null +++ b/ciphers/a1z26_cipher.cpp @@ -0,0 +1,162 @@ +/** + * @file + * @brief Implementation of the [A1Z26 + * cipher](https://www.dcode.fr/letter-number-cipher) + * @details The A1Z26 cipher is a simple substiution cipher where each letter is + * replaced by the number of the order they're in. For example, A corresponds to + * 1, B = 2, C = 3, etc. + * + * @author [Focusucof](https://github.com/Focusucof) + */ + +#include /// for std::transform and std::replace +#include /// for assert +#include /// for uint8_t +#include /// for IO operations +#include /// for std::map +#include /// for std::stringstream +#include /// for std::string +#include /// for std::vector + +/** + * @namespace ciphers + * @brief Algorithms for encryption and decryption + */ +namespace ciphers { +/** + * @namespace a1z26 + * @brief Functions for [A1Z26](https://www.dcode.fr/letter-number-cipher) + * encryption and decryption implementation + */ +namespace a1z26 { + +std::map a1z26_decrypt_map = { + {1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'}, {5, 'e'}, {6, 'f'}, {7, 'g'}, + {8, 'h'}, {9, 'i'}, {10, 'j'}, {11, 'k'}, {12, 'l'}, {13, 'm'}, {14, 'n'}, + {15, 'o'}, {16, 'p'}, {17, 'q'}, {18, 'r'}, {19, 's'}, {20, 't'}, {21, 'u'}, + {22, 'v'}, {23, 'w'}, {24, 'x'}, {25, 'y'}, {26, 'z'}, +}; + +std::map a1z26_encrypt_map = { + {'a', 1}, {'b', 2}, {'c', 3}, {'d', 4}, {'e', 5}, {'f', 6}, {'g', 7}, + {'h', 8}, {'i', 9}, {'j', 10}, {'k', 11}, {'l', 12}, {'m', 13}, {'n', 14}, + {'o', 15}, {'p', 16}, {'q', 17}, {'r', 18}, {'s', 19}, {'t', 20}, {'u', 21}, + {'v', 22}, {'w', 23}, {'x', 24}, {'y', 25}, {'z', 26}}; + +/** + * @brief a1z26 encryption implementation + * @param text is the plaintext input + * @returns encoded string with dashes to seperate letters + */ +std::string encrypt(std::string text) { + std::string result; + std::transform(text.begin(), text.end(), text.begin(), + ::tolower); // convert string to lowercase + std::replace(text.begin(), text.end(), ':', ' '); + for (char letter : text) { + if (letter != ' ') { + result += std::to_string( + a1z26_encrypt_map[letter]); // convert int to string and append + // to result + result += "-"; // space out each set of numbers with spaces + } else { + result.pop_back(); + result += ' '; + } + } + result.pop_back(); // remove leading dash + return result; +} + +/** + * @brief a1z26 decryption implementation + * @param text is the encrypted text input + * @param bReturnUppercase is if the decoded string should be in uppercase or + * not + * @returns the decrypted string in all uppercase or all lowercase + */ +std::string decrypt(const std::string& text, bool bReturnUppercase = false) { + std::string result; + + // split words seperated by spaces into a vector array + std::vector word_array; + std::stringstream sstream(text); + std::string word; + while (sstream >> word) { + word_array.push_back(word); + } + + for (auto& i : word_array) { + std::replace(i.begin(), i.end(), '-', ' '); + std::vector text_array; + + std::stringstream ss(i); + std::string res_text; + while (ss >> res_text) { + text_array.push_back(res_text); + } + + for (auto& i : text_array) { + result += a1z26_decrypt_map[stoi(i)]; + } + + result += ' '; + } + result.pop_back(); // remove any leading whitespace + + if (bReturnUppercase) { + std::transform(result.begin(), result.end(), result.begin(), ::toupper); + } + return result; +} + +} // namespace a1z26 +} // namespace ciphers + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::string input = "Hello World"; + std::string expected = "8-5-12-12-15 23-15-18-12-4"; + std::string output = ciphers::a1z26::encrypt(input); + + std::cout << "Input: " << input << std::endl; + std::cout << "Expected: " << expected << std::endl; + std::cout << "Output: " << output << std::endl; + assert(output == expected); + std::cout << "TEST PASSED"; + + // 2nd test + input = "12-15-23-5-18-3-1-19-5"; + expected = "lowercase"; + output = ciphers::a1z26::decrypt(input); + + std::cout << "Input: " << input << std::endl; + std::cout << "Expected: " << expected << std::endl; + std::cout << "Output: " << output << std::endl; + assert(output == expected); + std::cout << "TEST PASSED"; + + // 3rd test + input = "21-16-16-5-18-3-1-19-5"; + expected = "UPPERCASE"; + output = ciphers::a1z26::decrypt(input, true); + + std::cout << "Input: " << input << std::endl; + std::cout << "Expected: " << expected << std::endl; + std::cout << "Output: " << output << std::endl; + assert(output == expected); + std::cout << "TEST PASSED"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/ciphers/atbash_cipher.cpp b/ciphers/atbash_cipher.cpp index 04c330598..4f0d793f2 100644 --- a/ciphers/atbash_cipher.cpp +++ b/ciphers/atbash_cipher.cpp @@ -22,7 +22,8 @@ */ namespace ciphers { /** \namespace atbash - * \brief Functions for the [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + * \brief Functions for the [Atbash + * Cipher](https://en.wikipedia.org/wiki/Atbash) implementation */ namespace atbash { std::map atbash_cipher_map = { @@ -43,7 +44,7 @@ std::map atbash_cipher_map = { * @param text Plaintext to be encrypted * @returns encoded or decoded string */ -std::string atbash_cipher(std::string text) { +std::string atbash_cipher(const std::string& text) { std::string result; for (char letter : text) { result += atbash_cipher_map[letter]; diff --git a/data_structures/dsu_path_compression.cpp b/data_structures/dsu_path_compression.cpp new file mode 100644 index 000000000..022e632a7 --- /dev/null +++ b/data_structures/dsu_path_compression.cpp @@ -0,0 +1,213 @@ +/** + * @file + * @brief [DSU (Disjoint + * sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure) + * @details + * It is a very powerful data structure that keeps track of different + * clusters(sets) of elements, these sets are disjoint(doesnot have a common + * element). Disjoint sets uses cases : for finding connected components in a + * graph, used in Kruskal's algorithm for finding Minimum Spanning tree. + * Operations that can be performed: + * 1) UnionSet(i,j): add(element i and j to the set) + * 2) findSet(i): returns the representative of the set to which i belogngs to. + * 3) get_max(i),get_min(i) : returns the maximum and minimum + * Below is the class-based approach which uses the heuristic of path + * compression. Using path compression in findSet(i),we are able to get to the + * representative of i in O(1) time. + * @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT) + * @see dsu_union_rank.cpp + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +using std::cout; +using std::endl; +using std::vector; + +/** + * @brief Disjoint sets union data structure, class based representation. + * @param n number of elements + */ +class dsu { + private: + vector p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector setSize; ///< size of each chunk(set) + vector maxElement; ///< maximum of each set to which i belongs to + vector minElement; ///< minimum of each set to which i belongs to + public: + /** + * @brief contructor for initialising all data members. + * @param n number of elements + */ + explicit dsu(uint64_t n) { + p.assign(n, 0); + /// initially, all of them are their own parents + for (uint64_t i = 0; i < n; i++) { + p[i] = i; + } + /// initially all have depth are equals to zero + depth.assign(n, 0); + maxElement.assign(n, 0); + minElement.assign(n, 0); + for (uint64_t i = 0; i < n; i++) { + depth[i] = 0; + maxElement[i] = i; + minElement[i] = i; + } + setSize.assign(n, 0); + /// initially set size will be equals to one + for (uint64_t i = 0; i < n; i++) { + setSize[i] = 1; + } + } + + /** + * @brief Method to find the representative of the set to which i belongs + * to, T(n) = O(1) + * @param i element of some set + * @returns representative of the set to which i belongs to. + */ + uint64_t findSet(uint64_t i) { + /// using path compression + if (p[i] == i) { + return i; + } + return (p[i] = findSet(p[i])); + } + /** + * @brief Method that combines two disjoint sets to which i and j belongs to + * and make a single set having a common representative. + * @param i element of some set + * @param j element of some set + * @returns void + */ + void UnionSet(uint64_t i, uint64_t j) { + /// check if both belongs to the same set or not + if (isSame(i, j)) { + return; + } + + // we find the representative of the i and j + uint64_t x = findSet(i); + uint64_t y = findSet(j); + + /// always keeping the min as x + /// shallow tree + if (depth[x] > depth[y]) { + std::swap(x, y); + } + /// making the shallower root's parent the deeper root + p[x] = y; + + /// if same depth, then increase one's depth + if (depth[x] == depth[y]) { + depth[y]++; + } + /// total size of the resultant set + setSize[y] += setSize[x]; + /// changing the maximum elements + maxElement[y] = std::max(maxElement[x], maxElement[y]); + minElement[y] = std::min(minElement[x], minElement[y]); + } + /** + * @brief A utility function which check whether i and j belongs to + * same set or not + * @param i element of some set + * @param j element of some set + * @returns `true` if element `i` and `j` ARE in the same set + * @returns `false` if element `i` and `j` are NOT in same set + */ + bool isSame(uint64_t i, uint64_t j) { + if (findSet(i) == findSet(j)) { + return true; + } + return false; + } + /** + * @brief prints the minimum, maximum and size of the set to which i belongs + * to + * @param i element of some set + * @returns void + */ + vector get(uint64_t i) { + vector ans; + ans.push_back(get_min(i)); + ans.push_back(get_max(i)); + ans.push_back(size(i)); + return ans; + } + /** + * @brief A utility function that returns the size of the set to which i + * belongs to + * @param i element of some set + * @returns size of the set to which i belongs to + */ + uint64_t size(uint64_t i) { return setSize[findSet(i)]; } + /** + * @brief A utility function that returns the max element of the set to + * which i belongs to + * @param i element of some set + * @returns maximum of the set to which i belongs to + */ + uint64_t get_max(uint64_t i) { return maxElement[findSet(i)]; } + /** + * @brief A utility function that returns the min element of the set to + * which i belongs to + * @param i element of some set + * @returns minimum of the set to which i belongs to + */ + uint64_t get_min(uint64_t i) { return minElement[findSet(i)]; } +}; + +/** + * @brief Self-test implementations, 1st test + * @returns void + */ +static void test1() { + // the minimum, maximum, and size of the set + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + // set 1 + d.UnionSet(1, 2); // performs union operation on 1 and 2 + d.UnionSet(1, 4); // performs union operation on 1 and 4 + vector ans = {1, 4, 3}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.get(4).at(i) == ans[i]); // makes sure algorithm works fine + } + cout << "1st test passed!" << endl; +} +/** + * @brief Self-implementations, 2nd test + * @returns void + */ +static void test2() { + // the minimum, maximum, and size of the set + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + // set 1 + d.UnionSet(3, 5); + d.UnionSet(5, 6); + d.UnionSet(5, 7); + vector ans = {3, 7, 4}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.get(3).at(i) == ans[i]); // makes sure algorithm works fine + } + cout << "2nd test passed!" << endl; +} + +/** + * @brief Main function + * @returns 0 on exit + * */ +int main() { + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + + test1(); // run 1st test case + test2(); // run 2nd test case + + return 0; +} diff --git a/data_structures/dsu_union_rank.cpp b/data_structures/dsu_union_rank.cpp new file mode 100644 index 000000000..8936d6d69 --- /dev/null +++ b/data_structures/dsu_union_rank.cpp @@ -0,0 +1,187 @@ +/** + * @file + * @brief [DSU (Disjoint + * sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure) + * @details + * dsu : It is a very powerful data structure which keeps track of different + * clusters(sets) of elements, these sets are disjoint(doesnot have a common + * element). Disjoint sets uses cases : for finding connected components in a + * graph, used in Kruskal's algorithm for finding Minimum Spanning tree. + * Operations that can be performed: + * 1) UnionSet(i,j): add(element i and j to the set) + * 2) findSet(i): returns the representative of the set to which i belogngs to. + * 3) getParents(i): prints the parent of i and so on and so forth. + * Below is the class-based approach which uses the heuristic of union-ranks. + * Using union-rank in findSet(i),we are able to get to the representative of i + * in slightly delayed O(logN) time but it allows us to keep tracks of the + * parent of i. + * @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT) + * @see dsu_path_compression.cpp + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +using std::cout; +using std::endl; +using std::vector; + +/** + * @brief Disjoint sets union data structure, class based representation. + * @param n number of elements + */ +class dsu { + private: + vector p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector setSize; ///< size of each chunk(set) + public: + /** + * @brief constructor for initialising all data members + * @param n number of elements + */ + explicit dsu(uint64_t n) { + p.assign(n, 0); + /// initially all of them are their own parents + depth.assign(n, 0); + setSize.assign(n, 0); + for (uint64_t i = 0; i < n; i++) { + p[i] = i; + depth[i] = 0; + setSize[i] = 1; + } + } + /** + * @brief Method to find the representative of the set to which i belongs + * to, T(n) = O(logN) + * @param i element of some set + * @returns representative of the set to which i belongs to + */ + uint64_t findSet(uint64_t i) { + /// using union-rank + while (i != p[i]) { + i = p[i]; + } + return i; + } + /** + * @brief Method that combines two disjoint sets to which i and j belongs to + * and make a single set having a common representative. + * @param i element of some set + * @param j element of some set + * @returns void + */ + void unionSet(uint64_t i, uint64_t j) { + /// checks if both belongs to same set or not + if (isSame(i, j)) { + return; + } + /// we find representative of the i and j + uint64_t x = findSet(i); + uint64_t y = findSet(j); + + /// always keeping the min as x + /// in order to create a shallow tree + if (depth[x] > depth[y]) { + std::swap(x, y); + } + /// making the shallower tree, root parent of the deeper root + p[x] = y; + + /// if same depth, then increase one's depth + if (depth[x] == depth[y]) { + depth[y]++; + } + /// total size of the resultant set + setSize[y] += setSize[x]; + } + /** + * @brief A utility function which check whether i and j belongs to same set + * or not + * @param i element of some set + * @param j element of some set + * @returns `true` if element i and j are in same set + * @returns `false` if element i and j are not in same set + */ + bool isSame(uint64_t i, uint64_t j) { + if (findSet(i) == findSet(j)) { + return true; + } + return false; + } + /** + * @brief Method to print all the parents of i, or the path from i to + * representative. + * @param i element of some set + * @returns void + */ + vector getParents(uint64_t i) { + vector ans; + while (p[i] != i) { + ans.push_back(i); + i = p[i]; + } + ans.push_back(i); + return ans; + } +}; +/** + * @brief Self-implementations, 1st test + * @returns void + */ +static void test1() { + /* checks the parents in the resultant structures */ + uint64_t n = 10; ///< number of elements + dsu d(n + 1); ///< object of class disjoint sets + d.unionSet(2, 1); ///< performs union operation on 1 and 2 + d.unionSet(1, 4); + d.unionSet(8, 1); + d.unionSet(3, 5); + d.unionSet(5, 6); + d.unionSet(5, 7); + d.unionSet(9, 10); + d.unionSet(2, 10); + // keeping track of the changes using parent pointers + vector ans = {7, 5}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.getParents(7).at(i) == + ans[i]); // makes sure algorithm works fine + } + cout << "1st test passed!" << endl; +} +/** + * @brief Self-implementations, 2nd test + * @returns void + */ +static void test2() { + // checks the parents in the resultant structures + uint64_t n = 10; ///< number of elements + dsu d(n + 1); ///< object of class disjoint sets + d.unionSet(2, 1); /// performs union operation on 1 and 2 + d.unionSet(1, 4); + d.unionSet(8, 1); + d.unionSet(3, 5); + d.unionSet(5, 6); + d.unionSet(5, 7); + d.unionSet(9, 10); + d.unionSet(2, 10); + + /// keeping track of the changes using parent pointers + vector ans = {2, 1, 10}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.getParents(2).at(i) == + ans[i]); /// makes sure algorithm works fine + } + cout << "2nd test passed!" << endl; +} +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test1(); // run 1st test case + test2(); // run 2nd test case + + return 0; +} diff --git a/data_structures/stack_using_queue.cpp b/data_structures/stack_using_queue.cpp index 54a81a135..bd6a60e2b 100644 --- a/data_structures/stack_using_queue.cpp +++ b/data_structures/stack_using_queue.cpp @@ -3,13 +3,14 @@ * @details * Using 2 Queues inside the Stack class, we can easily implement Stack * data structure with heavy computation in push function. - * - * References used: [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) + * + * References used: + * [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) * @author [tushar2407](https://github.com/tushar2407) */ -#include /// for IO operations -#include /// for queue data structure -#include /// for assert +#include /// for assert +#include /// for IO operations +#include /// for queue data structure /** * @namespace data_strcutres @@ -18,66 +19,59 @@ namespace data_structures { /** * @namespace stack_using_queue - * @brief Functions for the [Stack Using Queue](https://www.studytonight.com/data-structures/stack-using-queue) implementation + * @brief Functions for the [Stack Using + * Queue](https://www.studytonight.com/data-structures/stack-using-queue) + * implementation */ namespace stack_using_queue { +/** + * @brief Stack Class implementation for basic methods of Stack Data Structure. + */ +struct Stack { + std::queue main_q; ///< stores the current state of the stack + std::queue auxiliary_q; ///< used to carry out intermediate + ///< operations to implement stack + uint32_t current_size = 0; ///< stores the current size of the stack + /** - * @brief Stack Class implementation for basic methods of Stack Data Structure. + * Returns the top most element of the stack + * @returns top element of the queue */ - struct Stack - { - std::queue main_q; ///< stores the current state of the stack - std::queue auxiliary_q; ///< used to carry out intermediate operations to implement stack - uint32_t current_size = 0; ///< stores the current size of the stack - - /** - * Returns the top most element of the stack - * @returns top element of the queue - */ - int top() - { - return main_q.front(); - } + int top() { return main_q.front(); } - /** - * @brief Inserts an element to the top of the stack. - * @param val the element that will be inserted into the stack - * @returns void - */ - void push(int val) - { - auxiliary_q.push(val); - while(!main_q.empty()) - { - auxiliary_q.push(main_q.front()); - main_q.pop(); - } - swap(main_q, auxiliary_q); - current_size++; - } - - /** - * @brief Removes the topmost element from the stack - * @returns void - */ - void pop() - { - if(main_q.empty()) { - return; - } + /** + * @brief Inserts an element to the top of the stack. + * @param val the element that will be inserted into the stack + * @returns void + */ + void push(int val) { + auxiliary_q.push(val); + while (!main_q.empty()) { + auxiliary_q.push(main_q.front()); main_q.pop(); - current_size--; } + swap(main_q, auxiliary_q); + current_size++; + } - /** - * @brief Utility function to return the current size of the stack - * @returns current size of stack - */ - int size() - { - return current_size; + /** + * @brief Removes the topmost element from the stack + * @returns void + */ + void pop() { + if (main_q.empty()) { + return; } - }; + main_q.pop(); + current_size--; + } + + /** + * @brief Utility function to return the current size of the stack + * @returns current size of stack + */ + int size() { return current_size; } +}; } // namespace stack_using_queue } // namespace data_structures @@ -85,30 +79,29 @@ namespace stack_using_queue { * @brief Self-test implementations * @returns void */ -static void test() -{ +static void test() { data_structures::stack_using_queue::Stack s; - s.push(1); /// insert an element into the stack - s.push(2); /// insert an element into the stack - s.push(3); /// insert an element into the stack - - assert(s.size()==3); /// size should be 3 - - assert(s.top()==3); /// topmost element in the stack should be 3 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==2); /// topmost element in the stack should now be 2 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==1); - - s.push(5); /// insert an element into the stack - assert(s.top()==5); /// topmost element in the stack should now be 5 - - s.pop(); /// remove the topmost element from the stack - assert(s.top()==1); /// topmost element in the stack should now be 1 - - assert(s.size()==1); /// size should be 1 + s.push(1); /// insert an element into the stack + s.push(2); /// insert an element into the stack + s.push(3); /// insert an element into the stack + + assert(s.size() == 3); /// size should be 3 + + assert(s.top() == 3); /// topmost element in the stack should be 3 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 2); /// topmost element in the stack should now be 2 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); + + s.push(5); /// insert an element into the stack + assert(s.top() == 5); /// topmost element in the stack should now be 5 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); /// topmost element in the stack should now be 1 + + assert(s.size() == 1); /// size should be 1 } /** @@ -119,8 +112,7 @@ static void test() * declared above. * @returns 0 on exit */ -int main() -{ +int main() { test(); // run self-test implementations return 0; } diff --git a/math/area.cpp b/math/area.cpp new file mode 100644 index 000000000..691fe91f0 --- /dev/null +++ b/math/area.cpp @@ -0,0 +1,279 @@ +/** + * @file + * @brief Implementations for the [area](https://en.wikipedia.org/wiki/Area) of + * various shapes + * @details The area of a shape is the amount of 2D space it takes up. + * All shapes have a formula to get the area of any given shape. + * These implementations support multiple return types. + * + * @author [Focusucof](https://github.com/Focusucof) + */ +#define _USE_MATH_DEFINES +#include /// for assert +#include /// for M_PI definition and pow() +#include +#include /// for uint16_t datatype +#include /// for IO operations + +/** + * @namespace math + * @brief Mathematical algorithms + */ +namespace math { +/** + * @brief area of a [square](https://en.wikipedia.org/wiki/Square) (l * l) + * @param length is the length of the square + * @returns area of square + */ +template +T square_area(T length) { + return length * length; +} + +/** + * @brief area of a [rectangle](https://en.wikipedia.org/wiki/Rectangle) (l * w) + * @param length is the length of the rectangle + * @param width is the width of the rectangle + * @returns area of the rectangle + */ +template +T rect_area(T length, T width) { + return length * width; +} + +/** + * @brief area of a [triangle](https://en.wikipedia.org/wiki/Triangle) (b * h / + * 2) + * @param base is the length of the bottom side of the triangle + * @param height is the length of the tallest point in the triangle + * @returns area of the triangle + */ +template +T triangle_area(T base, T height) { + return base * height / 2; +} + +/** + * @brief area of a [circle](https://en.wikipedia.org/wiki/Area_of_a_circle) (pi + * * r^2) + * @param radius is the radius of the circle + * @returns area of the circle + */ +template +T circle_area(T radius) { + return M_PI * pow(radius, 2); +} + +/** + * @brief area of a [parallelogram](https://en.wikipedia.org/wiki/Parallelogram) + * (b * h) + * @param base is the length of the bottom side of the parallelogram + * @param height is the length of the tallest point in the parallelogram + * @returns area of the parallelogram + */ +template +T parallelogram_area(T base, T height) { + return base * height; +} + +/** + * @brief surface area of a [cube](https://en.wikipedia.org/wiki/Cube) ( 6 * (l + * * l)) + * @param length is the length of the cube + * @returns surface area of the cube + */ +template +T cube_surface_area(T length) { + return 6 * length * length; +} + +/** + * @brief surface area of a [sphere](https://en.wikipedia.org/wiki/Sphere) ( 4 * + * pi * r^2) + * @param radius is the radius of the sphere + * @returns surface area of the sphere + */ +template +T sphere_surface_area(T radius) { + return 4 * M_PI * pow(radius, 2); +} + +/** + * @brief surface area of a [cylinder](https://en.wikipedia.org/wiki/Cylinder) + * (2 * pi * r * h + 2 * pi * r^2) + * @param radius is the radius of the cylinder + * @param height is the height of the cylinder + * @returns surface area of the cylinder + */ +template +T cylinder_surface_area(T radius, T height) { + return 2 * M_PI * radius * height + 2 * M_PI * pow(radius, 2); +} +} // namespace math + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // I/O variables for testing + uint16_t int_length = 0; // 16 bit integer length input + uint16_t int_width = 0; // 16 bit integer width input + uint16_t int_base = 0; // 16 bit integer base input + uint16_t int_height = 0; // 16 bit integer height input + uint16_t int_expected = 0; // 16 bit integer expected output + uint16_t int_area = 0; // 16 bit integer output + + float float_length = NAN; // float length input + float float_expected = NAN; // float expected output + float float_area = NAN; // float output + + double double_length = NAN; // double length input + double double_width = NAN; // double width input + double double_radius = NAN; // double radius input + double double_height = NAN; // double height input + double double_expected = NAN; // double expected output + double double_area = NAN; // double output + + // 1st test + int_length = 5; + int_expected = 25; + int_area = math::square_area(int_length); + + std::cout << "AREA OF A SQUARE (int)" << std::endl; + std::cout << "Input Length: " << int_length << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_area << std::endl; + assert(int_area == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 2nd test + float_length = 2.5; + float_expected = 6.25; + float_area = math::square_area(float_length); + + std::cout << "AREA OF A SQUARE (float)" << std::endl; + std::cout << "Input Length: " << float_length << std::endl; + std::cout << "Expected Output: " << float_expected << std::endl; + std::cout << "Output: " << float_area << std::endl; + assert(float_area == float_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 3rd test + int_length = 4; + int_width = 7; + int_expected = 28; + int_area = math::rect_area(int_length, int_width); + + std::cout << "AREA OF A RECTANGLE (int)" << std::endl; + std::cout << "Input Length: " << int_length << std::endl; + std::cout << "Input Width: " << int_width << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_area << std::endl; + assert(int_area == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 4th test + double_length = 2.5; + double_width = 5.7; + double_expected = 14.25; + double_area = math::rect_area(double_length, double_width); + + std::cout << "AREA OF A RECTANGLE (double)" << std::endl; + std::cout << "Input Length: " << double_length << std::endl; + std::cout << "Input Width: " << double_width << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_area << std::endl; + assert(double_area == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 5th test + int_base = 10; + int_height = 3; + int_expected = 15; + int_area = math::triangle_area(int_base, int_height); + + std::cout << "AREA OF A TRIANGLE" << std::endl; + std::cout << "Input Base: " << int_base << std::endl; + std::cout << "Input Height: " << int_height << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_area << std::endl; + assert(int_area == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 6th test + double_radius = 6; + double_expected = + 113.09733552923255; // rounded down because the double datatype + // truncates after 14 decimal places + double_area = math::circle_area(double_radius); + + std::cout << "AREA OF A CIRCLE" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_area << std::endl; + assert(double_area == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 7th test + int_base = 6; + int_height = 7; + int_expected = 42; + int_area = math::parallelogram_area(int_base, int_height); + + std::cout << "AREA OF A PARALLELOGRAM" << std::endl; + std::cout << "Input Base: " << int_base << std::endl; + std::cout << "Input Height: " << int_height << std::endl; + std::cout << "Expected Output: " << int_expected << std::endl; + std::cout << "Output: " << int_area << std::endl; + assert(int_area == int_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 8th test + double_length = 5.5; + double_expected = 181.5; + double_area = math::cube_surface_area(double_length); + + std::cout << "SURFACE AREA OF A CUBE" << std::endl; + std::cout << "Input Length: " << double_length << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_area << std::endl; + assert(double_area == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 9th test + double_radius = 10.0; + double_expected = 1256.6370614359172; // rounded down because the whole + // value gets truncated + double_area = math::sphere_surface_area(double_radius); + + std::cout << "SURFACE AREA OF A SPHERE" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_area << std::endl; + assert(double_area == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; + + // 10th test + double_radius = 4.0; + double_height = 7.0; + double_expected = 276.46015351590177; + double_area = math::cylinder_surface_area(double_radius, double_height); + + std::cout << "SURFACE AREA OF A CYLINDER" << std::endl; + std::cout << "Input Radius: " << double_radius << std::endl; + std::cout << "Input Height: " << double_height << std::endl; + std::cout << "Expected Output: " << double_expected << std::endl; + std::cout << "Output: " << double_area << std::endl; + assert(double_area == double_expected); + std::cout << "TEST PASSED" << std::endl << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/math/check_prime.cpp b/math/check_prime.cpp index 3c3ff2b62..a7b313551 100644 --- a/math/check_prime.cpp +++ b/math/check_prime.cpp @@ -7,12 +7,14 @@ * @brief * Reduced all possibilities of a number which cannot be prime. * Eg: No even number, except 2 can be a prime number, hence we will increment - * our loop with i+2 jumping on all odd numbers only. If number is <= 1 or if it - * is even except 2, break the loop and return false telling number is not - * prime. + * our loop with i+6 jumping and check for i or i+2 to be a factor of the + * number; if it's a factor then we will return false otherwise true after the + * loop terminates at the terminating condition which is (i*i<=num) */ -#include -#include + +#include /// for assert +#include /// for IO operations + /** * Function to check if the given number is prime or not. * @param num number to be checked. @@ -23,14 +25,13 @@ bool is_prime(T num) { bool result = true; if (num <= 1) { return false; - } else if (num == 2) { + } else if (num == 2 || num == 3) { return true; - } else if ((num & 1) == 0) { + } else if ((num % 2) == 0 || num % 3 == 0) { return false; - } - if (num >= 3) { - for (T i = 3; (i * i) <= (num); i = (i + 2)) { - if ((num % i) == 0) { + } else { + for (T i = 5; (i * i) <= (num); i = (i + 6)) { + if ((num % i) == 0 || (num % (i + 2) == 0)) { result = false; break; } diff --git a/math/integral_approximation2.cpp b/math/integral_approximation2.cpp index 706672d12..eed605e03 100644 --- a/math/integral_approximation2.cpp +++ b/math/integral_approximation2.cpp @@ -1,29 +1,34 @@ /** * @file - * @brief [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) + * @brief [Monte Carlo + * Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) * * @details - * In mathematics, Monte Carlo integration is a technique for numerical integration using random numbers. - * It is a particular Monte Carlo method that numerically computes a definite integral. - * While other algorithms usually evaluate the integrand at a regular grid, Monte Carlo randomly chooses points at which the integrand is evaluated. - * This method is particularly useful for higher-dimensional integrals. + * In mathematics, Monte Carlo integration is a technique for numerical + * integration using random numbers. It is a particular Monte Carlo method that + * numerically computes a definite integral. While other algorithms usually + * evaluate the integrand at a regular grid, Monte Carlo randomly chooses points + * at which the integrand is evaluated. This method is particularly useful for + * higher-dimensional integrals. * * This implementation supports arbitrary pdfs. - * These pdfs are sampled using the [Metropolis-Hastings algorithm](https://en.wikipedia.org/wiki/Metropolis–Hastings_algorithm). - * This can be swapped out by every other sampling techniques for example the inverse method. - * Metropolis-Hastings was chosen because it is the most general and can also be extended for a higher dimensional sampling space. + * These pdfs are sampled using the [Metropolis-Hastings + * algorithm](https://en.wikipedia.org/wiki/Metropolis–Hastings_algorithm). This + * can be swapped out by every other sampling techniques for example the inverse + * method. Metropolis-Hastings was chosen because it is the most general and can + * also be extended for a higher dimensional sampling space. * * @author [Domenic Zingsheim](https://github.com/DerAndereDomenic) */ -#define _USE_MATH_DEFINES /// for M_PI on windows -#include /// for math functions -#include /// for fixed size data types -#include /// for time to initialize rng -#include /// for function pointers -#include /// for std::cout -#include /// for random number generation -#include /// for std::vector +#define _USE_MATH_DEFINES /// for M_PI on windows +#include /// for math functions +#include /// for fixed size data types +#include /// for time to initialize rng +#include /// for function pointers +#include /// for std::cout +#include /// for random number generation +#include /// for std::vector /** * @namespace math @@ -32,25 +37,34 @@ namespace math { /** * @namespace monte_carlo - * @brief Functions for the [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) implementation + * @brief Functions for the [Monte Carlo + * Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) + * implementation */ namespace monte_carlo { -using Function = std::function; /// short-hand for std::functions used in this implementation +using Function = std::function; /// short-hand for std::functions used in this implementation /** * @brief Generate samples according to some pdf - * @details This function uses Metropolis-Hastings to generate random numbers. It generates a sequence of random numbers by using a markov chain. - * Therefore, we need to define a start_point and the number of samples we want to generate. - * Because the first samples generated by the markov chain may not be distributed according to the given pdf, one can specify how many samples + * @details This function uses Metropolis-Hastings to generate random numbers. + * It generates a sequence of random numbers by using a markov chain. Therefore, + * we need to define a start_point and the number of samples we want to + * generate. Because the first samples generated by the markov chain may not be + * distributed according to the given pdf, one can specify how many samples * should be discarded before storing samples. * @param start_point The starting point of the markov chain * @param pdf The pdf to sample * @param num_samples The number of samples to generate * @param discard How many samples should be discarded at the start - * @returns A vector of size num_samples with samples distributed according to the pdf + * @returns A vector of size num_samples with samples distributed according to + * the pdf */ -std::vector generate_samples(const double& start_point, const Function& pdf, const uint32_t& num_samples, const uint32_t& discard = 100000) { +std::vector generate_samples(const double& start_point, + const Function& pdf, + const uint32_t& num_samples, + const uint32_t& discard = 100000) { std::vector samples; samples.reserve(num_samples); @@ -61,19 +75,19 @@ std::vector generate_samples(const double& start_point, const Function& std::normal_distribution normal(0.0, 1.0); generator.seed(time(nullptr)); - for(uint32_t t = 0; t < num_samples + discard; ++t) { + for (uint32_t t = 0; t < num_samples + discard; ++t) { // Generate a new proposal according to some mutation strategy. // This is arbitrary and can be swapped. double x_dash = normal(generator) + x_t; - double acceptance_probability = std::min(pdf(x_dash)/pdf(x_t), 1.0); + double acceptance_probability = std::min(pdf(x_dash) / pdf(x_t), 1.0); double u = uniform(generator); // Accept "new state" according to the acceptance_probability - if(u <= acceptance_probability) { + if (u <= acceptance_probability) { x_t = x_dash; } - if(t >= discard) { + if (t >= discard) { samples.push_back(x_t); } } @@ -92,13 +106,17 @@ std::vector generate_samples(const double& start_point, const Function& * @param function The function to integrate * @param pdf The pdf to sample * @param num_samples The number of samples used to approximate the integral - * @returns The approximation of the integral according to 1/N \sum_{i}^N f(x_i) / p(x_i) + * @returns The approximation of the integral according to 1/N \sum_{i}^N f(x_i) + * / p(x_i) */ -double integral_monte_carlo(const double& start_point, const Function& function, const Function& pdf, const uint32_t& num_samples = 1000000) { +double integral_monte_carlo(const double& start_point, const Function& function, + const Function& pdf, + const uint32_t& num_samples = 1000000) { double integral = 0.0; - std::vector samples = generate_samples(start_point, pdf, num_samples); + std::vector samples = + generate_samples(start_point, pdf, num_samples); - for(double sample : samples) { + for (double sample : samples) { integral += function(sample) / pdf(sample); } @@ -113,8 +131,13 @@ double integral_monte_carlo(const double& start_point, const Function& function, * @returns void */ static void test() { - std::cout << "Disclaimer: Because this is a randomized algorithm," << std::endl; - std::cout << "it may happen that singular samples deviate from the true result." << std::endl << std::endl;; + std::cout << "Disclaimer: Because this is a randomized algorithm," + << std::endl; + std::cout + << "it may happen that singular samples deviate from the true result." + << std::endl + << std::endl; + ; math::monte_carlo::Function f; math::monte_carlo::Function pdf; @@ -122,60 +145,58 @@ static void test() { double lower_bound = 0, upper_bound = 0; /* \int_{-2}^{2} -x^2 + 4 dx */ - f = [&](double& x) { - return -x*x + 4.0; - }; + f = [&](double& x) { return -x * x + 4.0; }; lower_bound = -2.0; upper_bound = 2.0; pdf = [&](double& x) { - if(x >= lower_bound && x <= -1.0) { + if (x >= lower_bound && x <= -1.0) { return 0.1; } - if(x <= upper_bound && x >= 1.0) { + if (x <= upper_bound && x >= 1.0) { return 0.1; } - if(x > -1.0 && x < 1.0) { + if (x > -1.0 && x < 1.0) { return 0.4; } return 0.0; }; - integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf); + integral = math::monte_carlo::integral_monte_carlo( + (upper_bound - lower_bound) / 2.0, f, pdf); - std::cout << "This number should be close to 10.666666: " << integral << std::endl; + std::cout << "This number should be close to 10.666666: " << integral + << std::endl; /* \int_{0}^{1} e^x dx */ - f = [&](double& x) { - return std::exp(x); - }; + f = [&](double& x) { return std::exp(x); }; lower_bound = 0.0; upper_bound = 1.0; pdf = [&](double& x) { - if(x >= lower_bound && x <= 0.2) { + if (x >= lower_bound && x <= 0.2) { return 0.1; } - if(x > 0.2 && x <= 0.4) { + if (x > 0.2 && x <= 0.4) { return 0.4; } - if(x > 0.4 && x < upper_bound) { + if (x > 0.4 && x < upper_bound) { return 1.5; } return 0.0; }; - integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf); + integral = math::monte_carlo::integral_monte_carlo( + (upper_bound - lower_bound) / 2.0, f, pdf); - std::cout << "This number should be close to 1.7182818: " << integral << std::endl; + std::cout << "This number should be close to 1.7182818: " << integral + << std::endl; /* \int_{-\infty}^{\infty} sinc(x) dx, sinc(x) = sin(pi * x) / (pi * x) This is a difficult integral because of its infinite domain. Therefore, it may deviate largely from the expected result. */ - f = [&](double& x) { - return std::sin(M_PI * x) / (M_PI * x); - }; + f = [&](double& x) { return std::sin(M_PI * x) / (M_PI * x); }; pdf = [&](double& x) { return 1.0 / std::sqrt(2.0 * M_PI) * std::exp(-x * x / 2.0); @@ -183,7 +204,8 @@ static void test() { integral = math::monte_carlo::integral_monte_carlo(0.0, f, pdf, 10000000); - std::cout << "This number should be close to 1.0: " << integral << std::endl; + std::cout << "This number should be close to 1.0: " << integral + << std::endl; } /** diff --git a/operations_on_datastructures/array_right_rotation.cpp b/operations_on_datastructures/array_right_rotation.cpp index 8b01a2003..65e8536f4 100644 --- a/operations_on_datastructures/array_right_rotation.cpp +++ b/operations_on_datastructures/array_right_rotation.cpp @@ -1,27 +1,175 @@ -#include -using namespace std; -int main() { - int n, k; - cout << "Enter size of array=\t"; - cin >> n; - cout << "Enter Number of indices u want to rotate the array to right=\t"; - cin >> k; - int a[n]; - cout << "Enter elements of array=\t"; - for (int i = 0; i < n; i++) cin >> a[i]; - int temp = 0; - for (int i = 0; i < k; i++) { - temp = a[n - 1]; - for (int j = n - 1; j >= 0; j--) { - if (j == 0) { - a[j] = temp; - } else { - a[j] = a[j - 1]; - } - } - } - cout << "Your rotated array is=\t"; - for (int i = 0; i < n; i++) { - cout << a[i] << " "; +/** + * @file + * @brief Implementation for the [Array right + * Rotation](https://www.javatpoint.com/program-to-right-rotate-the-elements-of-an-array) + * algorithm. + * @details Shifting an array to the right involves moving each element of the + * array so that it occupies a position of a certain shift value after its + * current one. This implementation uses a result vector and does not mutate the + * input. + * @see array_left_rotation.cpp + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @brief Prints the values of a vector sequentially, ending with a newline + * character. + * @param array Reference to the array to be printed + * @returns void + */ +void print(const std::vector &array) { + for (int32_t i : array) { + std::cout << i << " "; /// Print each value in the array } + std::cout << "\n"; /// Print newline +} + +/** + * @brief Shifts the given vector to the right by the shift amount and returns a + * new vector with the result. The original vector is not mutated. + * @details Shifts the values of the vector, by creating a new vector and adding + * values from the shift index to the end, then appending the rest of the + * elements to the start of the vector. + * @param array A reference to the input std::vector + * @param shift The amount to be shifted to the right + * @returns A std::vector with the shifted values + */ +std::vector shift_right(const std::vector &array, + size_t shift) { + if (array.size() <= shift) { + return {}; ///< We got an invalid shift, return empty array + } + std::vector res(array.size()); ///< Result array + for (size_t i = shift; i < array.size(); i++) { + res[i] = array[i - shift]; ///< Add values after the shift index + } + for (size_t i = 0; i < shift; i++) { + res[i] = + array[array.size() - shift + i]; ///< Add the values from the start + } + return res; +} + +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check Union of Two Arrays. + */ +namespace tests { +using operations_on_datastructures::print; +using operations_on_datastructures::shift_right; +/** + * @brief A Test to check an simple case + * @returns void + */ +void test1() { + std::cout << "TEST CASE 1\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {4, 5, 1, 2, 3}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_right(arr, 2); + std::vector expected = {4, 5, 1, 2, 3}; + assert(res == expected); + print(res); ///< Should print 4 5 1 2 3 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an empty vector + * @returns void + */ +void test2() { + std::cout << "TEST CASE 2\n"; + std::cout << "Initialized arr = {}\n"; + std::cout << "Expected result: {}\n"; + std::vector arr = {}; + std::vector res = shift_right(arr, 2); + std::vector expected = {}; + assert(res == expected); + print(res); ///< Should print empty newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an invalid shift value + * @returns void + */ +void test3() { + std::cout << "TEST CASE 3\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_right(arr, 7); ///< 7 > 5 + std::vector expected = {}; + assert(res == expected); + print(res); ///< Should print empty newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check a very large input + * @returns void + */ +void test4() { + std::cout << "TEST CASE 4\n"; + std::cout << "Initialized arr = {2, 4, ..., 420}\n"; + std::cout << "Expected result: {420, 2, 4, ..., 418}\n"; + std::vector arr; + for (int i = 1; i <= 210; i++) { + arr.push_back(i * 2); + } + print(arr); + std::vector res = shift_right(arr, 1); + std::vector expected; + expected.push_back(420); + for (int i = 0; i < 209; i++) { + expected.push_back(arr[i]); + } + assert(res == expected); + print(res); ///< Should print {420, 2, 4, ..., 418} + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check a shift of zero + * @returns void + */ +void test5() { + std::cout << "TEST CASE 5\n"; + std::cout << "Initialized arr = {1, 2, 3, 4, 5}\n"; + std::cout << "Expected result: {1, 2, 3, 4, 5}\n"; + std::vector arr = {1, 2, 3, 4, 5}; + std::vector res = shift_right(arr, 0); + assert(res == arr); + print(res); ///< Should print 1 2 3 4 5 + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of shift_right() function + * @returns void + */ +static void test() { + tests::test1(); + tests::test2(); + tests::test3(); + tests::test4(); + tests::test5(); +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; } diff --git a/operations_on_datastructures/intersection_of_2_arrays.cpp b/operations_on_datastructures/intersection_of_2_arrays.cpp deleted file mode 100644 index 8a3b27edf..000000000 --- a/operations_on_datastructures/intersection_of_2_arrays.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include -int main() { - int i, j, m, n; - cout << "Enter size of array 1:"; - cin >> m; - cout << "Enter size of array 2:"; - cin >> n; - int a[m]; - int b[n]; - cout << "Enter elements of array 1:"; - for (i = 0; i < m; i++) cin >> a[i]; - for (i = 0; i < n; i++) cin >> b[i]; - i = 0; - j = 0; - while ((i < m) && (j < n)) { - if (a[i] < b[j]) - i++; - else if (a[i] > b[j]) - j++; - else { - cout << a[i++] << " "; - j++; - } - } - return 0; -} diff --git a/operations_on_datastructures/intersection_of_two_arrays.cpp b/operations_on_datastructures/intersection_of_two_arrays.cpp new file mode 100644 index 000000000..c660f505b --- /dev/null +++ b/operations_on_datastructures/intersection_of_two_arrays.cpp @@ -0,0 +1,203 @@ +/** + * @file + * @brief Implementation for the [Intersection of two sorted + * Arrays](https://en.wikipedia.org/wiki/Intersection_(set_theory)) + * algorithm. + * @details The intersection of two arrays is the collection of all the elements + * that are common in both the first and second arrays. This implementation uses + * ordered arrays, and an algorithm to correctly order them and return the + * result as a new array (vector). + * @see union_of_two_arrays.cpp + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// for std::sort +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @brief Prints the values of a vector sequentially, ending with a newline + * character. + * @param array Reference to the array to be printed + * @returns void + */ +void print(const std::vector &array) { + for (int32_t i : array) { + std::cout << i << " "; /// Print each value in the array + } + std::cout << "\n"; /// Print newline +} + +/** + * @brief Gets the intersection of two sorted arrays, and returns them in a + * vector. + * @details An algorithm is used that compares the elements of the two vectors, + * incrementing the index of the smaller of the two. If the elements are the + * same, the element is appended to the result array to be returned. + * @param first A std::vector of sorted integer values + * @param second A std::vector of sorted integer values + * @returns A std::vector of the intersection of the two arrays, in ascending + * order + */ +std::vector get_intersection(const std::vector &first, + const std::vector &second) { + std::vector res; ///< Vector to hold the intersection + size_t f_index = 0; ///< Index for the first array + size_t s_index = 0; ///< Index for the second array + size_t f_length = first.size(); ///< Length of first array + size_t s_length = second.size(); ///< Length of second array + + while (f_index < f_length && s_index < s_length) { + if (first[f_index] < second[s_index]) { + f_index++; ///< Increment index of second array + } else if (first[f_index] > second[s_index]) { + s_index++; ///< Increment index of second array + } else { + if ((res.size() == 0) || (first[f_index] != res.back())) { + res.push_back( + first[f_index]); ///< Add the element if it is unique + } + f_index++; ///< Increment index of first array + s_index++; ///< Increment index of second array too + } + } + return res; +} + +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check intersection of Two Arrays. + */ +namespace tests { +using operations_on_datastructures::get_intersection; +using operations_on_datastructures::print; +/** + * @brief A Test to check an edge case (two empty arrays) + * @returns void + */ +void test1() { + std::cout << "TEST CASE 1\n"; + std::cout << "Intialized a = {} b = {}\n"; + std::cout << "Expected result: {}\n"; + std::vector a = {}; + std::vector b = {}; + std::vector result = get_intersection(a, b); + assert(result == a); ///< Check if result is empty + print(result); ///< Should only print newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an edge case (one empty array) + * @returns void + */ +void test2() { + std::cout << "TEST CASE 2\n"; + std::cout << "Intialized a = {} b = {2, 3}\n"; + std::cout << "Expected result: {}\n"; + std::vector a = {}; + std::vector b = {2, 3}; + std::vector result = get_intersection(a, b); + assert(result == a); ///< Check if result is equal to a + print(result); ///< Should only print newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a simple test case + * @returns void + */ +void test3() { + std::cout << "TEST CASE 3\n"; + std::cout << "Intialized a = {4, 6} b = {3, 6}\n"; + std::cout << "Expected result: {6}\n"; + std::vector a = {4, 6}; + std::vector b = {3, 6}; + std::vector result = get_intersection(a, b); + std::vector expected = {6}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 6 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with duplicate values + * @returns void + */ +void test4() { + std::cout << "TEST CASE 4\n"; + std::cout << "Intialized a = {4, 6, 6, 6} b = {2, 4, 4, 6}\n"; + std::cout << "Expected result: {4, 6}\n"; + std::vector a = {4, 6, 6, 6}; + std::vector b = {2, 4, 4, 6}; + std::vector result = get_intersection(a, b); + std::vector expected = {4, 6}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 4 6 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a harder test case + * @returns void + */ +void test5() { + std::cout << "TEST CASE 5\n"; + std::cout << "Intialized a = {1, 2, 3, 4, 6, 7, 9} b = {2, 3, 4, 5}\n"; + std::cout << "Expected result: {2, 3, 4}\n"; + std::vector a = {1, 2, 3, 4, 6, 7, 9}; + std::vector b = {2, 3, 4, 5}; + std::vector result = get_intersection(a, b); + std::vector expected = {2, 3, 4}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 2 3 4 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with an array sorted using + * std::sort + * @returns void + */ +void test6() { + std::cout << "TEST CASE 6\n"; + std::cout << "Intialized a = {1, 3, 3, 2, 5, 9, 4, 7, 3, 2} "; + std::cout << "b = {11, 3, 7, 8, 6}\n"; + std::cout << "Expected result: {3, 7}\n"; + std::vector a = {1, 3, 3, 2, 5, 9, 4, 7, 3, 2}; + std::vector b = {11, 3, 7, 8, 6}; + std::sort(a.begin(), a.end()); ///< Sort vector a + std::sort(b.begin(), b.end()); ///< Sort vector b + std::vector result = get_intersection(a, b); + std::vector expected = {3, 7}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 3 7 + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of get_intersection() function + * @returns void + */ +static void test() { + tests::test1(); + tests::test2(); + tests::test3(); + tests::test4(); + tests::test5(); + tests::test6(); +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/operations_on_datastructures/union_of_2_arrays.cpp b/operations_on_datastructures/union_of_2_arrays.cpp deleted file mode 100644 index cdacf1d2e..000000000 --- a/operations_on_datastructures/union_of_2_arrays.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -int main() { - int m, n, i = 0, j = 0; - cout << "Enter size of both arrays:"; - cin >> m >> n; - int a[m]; - int b[n]; - cout << "Enter elements of array 1:"; - for (i = 0; i < m; i++) cin >> a[i]; - cout << "Enter elements of array 2:"; - for (i = 0; i < n; i++) cin >> b[i]; - i = 0; - j = 0; - while ((i < m) && (j < n)) { - if (a[i] < b[j]) - cout << a[i++] << " "; - else if (a[i] > b[j]) - cout << b[j++] << " "; - else { - cout << a[i++]; - j++; - } - } - while (i < m) cout << a[i++] << " "; - while (j < n) cout << b[j++] << " "; - return 0; -} diff --git a/operations_on_datastructures/union_of_two_arrays.cpp b/operations_on_datastructures/union_of_two_arrays.cpp new file mode 100644 index 000000000..8fd75bde7 --- /dev/null +++ b/operations_on_datastructures/union_of_two_arrays.cpp @@ -0,0 +1,220 @@ +/** + * @file + * @brief Implementation for the [Union of two sorted + * Arrays](https://en.wikipedia.org/wiki/Union_(set_theory)) + * algorithm. + * @details The Union of two arrays is the collection of all the unique elements + * in the first array, combined with all of the unique elements of a second + * array. This implementation uses ordered arrays, and an algorithm to correctly + * order them and return the result as a new array (vector). + * @see intersection_of_two_arrays.cpp + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// for std::sort +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @brief Prints the values of a vector sequentially, ending with a newline + * character. + * @param array Reference to the array to be printed + * @returns void + */ +void print(const std::vector &array) { + for (int32_t i : array) { + std::cout << i << " "; /// Print each value in the array + } + std::cout << "\n"; /// Print newline +} + +/** + * @brief Gets the union of two sorted arrays, and returns them in a + * vector. + * @details An algorithm is used that compares the elements of the two vectors, + * appending the one that has a lower value, and incrementing the index for that + * array. If one of the arrays reaches its end, all the elements of the other + * are appended to the resultant vector. + * @param first A std::vector of sorted integer values + * @param second A std::vector of sorted integer values + * @returns A std::vector of the union of the two arrays, in ascending order + */ +std::vector get_union(const std::vector &first, + const std::vector &second) { + std::vector res; ///< Vector to hold the union + size_t f_index = 0; ///< Index for the first array + size_t s_index = 0; ///< Index for the second array + size_t f_length = first.size(); ///< Length of first array + size_t s_length = second.size(); ///< Length of second array + int32_t next = 0; ///< Integer to store value of the next element + + while (f_index < f_length && s_index < s_length) { + if (first[f_index] < second[s_index]) { + next = first[f_index]; ///< Append from first array + f_index++; ///< Increment index of second array + } else if (first[f_index] > second[s_index]) { + next = second[s_index]; ///< Append from second array + s_index++; ///< Increment index of second array + } else { + next = first[f_index]; ///< Element is the same in both + f_index++; ///< Increment index of first array + s_index++; ///< Increment index of second array too + } + if ((res.size() == 0) || (next != res.back())) { + res.push_back(next); ///< Add the element if it is unique + } + } + while (f_index < f_length) { + next = first[f_index]; ///< Add remaining elements + if ((res.size() == 0) || (next != res.back())) { + res.push_back(next); ///< Add the element if it is unique + } + f_index++; + } + while (s_index < s_length) { + next = second[s_index]; ///< Add remaining elements + if ((res.size() == 0) || (next != res.back())) { + res.push_back(next); ///< Add the element if it is unique + } + s_index++; + } + return res; +} + +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check Union of Two Arrays. + */ +namespace tests { +using operations_on_datastructures::get_union; +using operations_on_datastructures::print; +/** + * @brief A Test to check an edge case (two empty arrays) + * @returns void + */ +void test1() { + std::cout << "TEST CASE 1\n"; + std::cout << "Intialized a = {} b = {}\n"; + std::cout << "Expected result: {}\n"; + std::vector a = {}; + std::vector b = {}; + std::vector result = get_union(a, b); + assert(result == a); ///< Check if result is empty + print(result); ///< Should only print newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an edge case (one empty array) + * @returns void + */ +void test2() { + std::cout << "TEST CASE 2\n"; + std::cout << "Intialized a = {} b = {2, 3}\n"; + std::cout << "Expected result: {2, 3}\n"; + std::vector a = {}; + std::vector b = {2, 3}; + std::vector result = get_union(a, b); + assert(result == b); ///< Check if result is equal to b + print(result); ///< Should print 2 3 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a simple test case + * @returns void + */ +void test3() { + std::cout << "TEST CASE 3\n"; + std::cout << "Intialized a = {4, 6} b = {2, 3}\n"; + std::cout << "Expected result: {2, 3, 4, 6}\n"; + std::vector a = {4, 6}; + std::vector b = {2, 3}; + std::vector result = get_union(a, b); + std::vector expected = {2, 3, 4, 6}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 2 3 4 6 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with duplicate values + * @returns void + */ +void test4() { + std::cout << "TEST CASE 4\n"; + std::cout << "Intialized a = {4, 6, 6, 7} b = {2, 3, 4}\n"; + std::cout << "Expected result: {2, 3, 4, 6, 7}\n"; + std::vector a = {4, 6, 6, 7}; + std::vector b = {2, 3, 4}; + std::vector result = get_union(a, b); + std::vector expected = {2, 3, 4, 6, 7}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 2 3 4 6 7 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a harder test case + * @returns void + */ +void test5() { + std::cout << "TEST CASE 5\n"; + std::cout << "Intialized a = {1, 4, 6, 7, 9} b = {2, 3, 5}\n"; + std::cout << "Expected result: {1, 2, 3, 4, 5, 6, 7, 9}\n"; + std::vector a = {1, 4, 6, 7, 9}; + std::vector b = {2, 3, 5}; + std::vector result = get_union(a, b); + std::vector expected = {1, 2, 3, 4, 5, 6, 7, 9}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 1 2 3 4 5 6 7 9 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with an array sorted using + * std::sort + * @returns void + */ +void test6() { + std::cout << "TEST CASE 6\n"; + std::cout << "Intialized a = {1, 3, 3, 2, 5, 9, 4, 3, 2} "; + std::cout << "b = {11, 3, 7, 8, 6}\n"; + std::cout << "Expected result: {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}\n"; + std::vector a = {1, 3, 3, 2, 5, 9, 4, 3, 2}; + std::vector b = {11, 3, 7, 8, 6}; + std::sort(a.begin(), a.end()); ///< Sort vector a + std::sort(b.begin(), b.end()); ///< Sort vector b + std::vector result = get_union(a, b); + std::vector expected = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 1 2 3 4 5 6 7 8 9 11 + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of get_union() function + * @returns void + */ +static void test() { + tests::test1(); + tests::test2(); + tests::test3(); + tests::test4(); + tests::test5(); + tests::test6(); +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/range_queries/segtree.cpp b/range_queries/segtree.cpp index bc03b5428..71e6890fb 100644 --- a/range_queries/segtree.cpp +++ b/range_queries/segtree.cpp @@ -144,7 +144,7 @@ void update(std::vector *segtree, std::vector *lazy, * @returns void */ static void test() { - int64_t max = static_cast(2 * pow(2, ceil(log2(7))) - 1); + auto max = static_cast(2 * pow(2, ceil(log2(7))) - 1); assert(max == 15); std::vector arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max); @@ -172,7 +172,7 @@ int main() { uint64_t n = 0; std::cin >> n; - uint64_t max = static_cast(2 * pow(2, ceil(log2(n))) - 1); + auto max = static_cast(2 * pow(2, ceil(log2(n))) - 1); std::vector arr(n), lazy(max), segtree(max); int choice = 0; diff --git a/sorting/selection_sort.cpp b/sorting/selection_sort.cpp deleted file mode 100644 index 3854f52e6..000000000 --- a/sorting/selection_sort.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Selection Sort - -#include -using namespace std; - -int main() { - int Array[6]; - cout << "\nEnter any 6 Numbers for Unsorted Array : "; - - // Input - for (int i = 0; i < 6; i++) { - cin >> Array[i]; - } - - // Selection Sorting - for (int i = 0; i < 6; i++) { - int min = i; - for (int j = i + 1; j < 6; j++) { - if (Array[j] < Array[min]) { - min = j; // Finding the smallest number in Array - } - } - int temp = Array[i]; - Array[i] = Array[min]; - Array[min] = temp; - } - - // Output - cout << "\nSorted Array : "; - for (int i = 0; i < 6; i++) { - cout << Array[i] << "\t"; - } -} diff --git a/sorting/selection_sort_iterative.cpp b/sorting/selection_sort_iterative.cpp new file mode 100644 index 000000000..a9adac089 --- /dev/null +++ b/sorting/selection_sort_iterative.cpp @@ -0,0 +1,126 @@ +/****************************************************************************** + * @file + * @brief Implementation of the [Selection + * sort](https://en.wikipedia.org/wiki/Selection_sort) implementation using + * swapping + * @details + * The selection sort algorithm divides the input vector into two parts: a + * sorted subvector of items which is built up from left to right at the front + * (left) of the vector, and a subvector of the remaining unsorted items that + * occupy the rest of the vector. Initially, the sorted subvector is empty, and + * the unsorted subvector is the entire input vector. The algorithm proceeds by + * finding the smallest (or largest, depending on the sorting order) element in + * the unsorted subvector, exchanging (swapping) it with the leftmost unsorted + * element (putting it in sorted order), and moving the subvector boundaries one + * element to the right. + * + * ### Implementation + * + * SelectionSort + * The algorithm divides the input vector into two parts: the subvector of items + * already sorted, which is built up from left to right. Initially, the sorted + * subvector is empty and the unsorted subvector is the entire input vector. The + * algorithm proceeds by finding the smallest element in the unsorted subvector, + * exchanging (swapping) it with the leftmost unsorted element (putting it in + * sorted order), and moving the subvector boundaries one element to the right. + * + * @author [Lajat Manekar](https://github.com/Lazeeez) + * @author Unknown author + *******************************************************************************/ +#include /// for std::is_sorted +#include /// for std::assert +#include /// for IO operations +#include /// for std::vector + +/****************************************************************************** + * @namespace sorting + * @brief Sorting algorithms + *******************************************************************************/ +namespace sorting { +/****************************************************************************** + * @brief The main function which implements Selection sort + * @param arr vector to be sorted + * @param len length of vector to be sorted + * @returns @param array resultant sorted vector + *******************************************************************************/ + +std::vector selectionSort(const std::vector &arr, + uint64_t len) { + std::vector array( + arr.begin(), + arr.end()); // declare a vector in which result will be stored + for (uint64_t it = 0; it < len; ++it) { + uint64_t min = it; // set min value + for (uint64_t it2 = it + 1; it2 < len; ++it2) { + if (array[it2] < array[min]) { // check which element is smaller + min = it2; // store index of smallest element to min + } + } + + if (min != it) { // swap if min does not match to i + uint64_t tmp = array[min]; + array[min] = array[it]; + array[it] = tmp; + } + } + + return array; // return sorted vector +} +} // namespace sorting + +/******************************************************************************* + * @brief Self-test implementations + * @returns void + *******************************************************************************/ +static void test() { + // testcase #1 + // [1, 0, 0, 1, 1, 0, 2, 1] returns [0, 0, 0, 1, 1, 1, 1, 2] + std::vector vector1 = {1, 0, 0, 1, 1, 0, 2, 1}; + uint64_t vector1size = vector1.size(); + std::cout << "1st test... "; + std::vector result_test1; + result_test1 = sorting::selectionSort(vector1, vector1size); + assert(std::is_sorted(result_test1.begin(), result_test1.end())); + std::cout << "Passed" << std::endl; + + // testcase #2 + // [19, 22, 540, 241, 156, 140, 12, 1] returns [1, 12, 19, 22, 140, 156, + // 241,540] + std::vector vector2 = {19, 22, 540, 241, 156, 140, 12, 1}; + uint64_t vector2size = vector2.size(); + std::cout << "2nd test... "; + std::vector result_test2; + result_test2 = sorting::selectionSort(vector2, vector2size); + assert(std::is_sorted(result_test2.begin(), result_test2.end())); + std::cout << "Passed" << std::endl; + + // testcase #3 + // [11, 20, 30, 41, 15, 60, 82, 15] returns [11, 15, 15, 20, 30, 41, 60, 82] + std::vector vector3 = {11, 20, 30, 41, 15, 60, 82, 15}; + uint64_t vector3size = vector3.size(); + std::cout << "3rd test... "; + std::vector result_test3; + result_test3 = sorting::selectionSort(vector3, vector3size); + assert(std::is_sorted(result_test3.begin(), result_test3.end())); + std::cout << "Passed" << std::endl; + + // testcase #4 + // [1, 9, 11, 546, 26, 65, 212, 14, -11] returns [-11, 1, 9, 11, 14, 26, 65, + // 212, 546] + std::vector vector4 = {1, 9, 11, 546, 26, 65, 212, 14}; + uint64_t vector4size = vector2.size(); + std::cout << "4th test... "; + std::vector result_test4; + result_test4 = sorting::selectionSort(vector4, vector4size); + assert(std::is_sorted(result_test4.begin(), result_test4.end())); + std::cout << "Passed" << std::endl; +} + +/******************************************************************************* + * @brief Main function + * @returns 0 on exit + *******************************************************************************/ +int main() { + test(); // run self-test implementations + return 0; +}