diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2ff8cb72c..09434e085 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ You can add new algorithms or data structures which are **not present in the rep - Please use the directory structure of the repository. - Make sure the file extensions should be `*.hpp`, `*.h` or `*.cpp`. - Don't use **`bits/stdc++.h`** because this is quite Linux-specific and slows down the compilation process. -- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords +- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords. - If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines). - You can suggest reasonable changes to existing algorithms. - Strictly use snake_case (underscore_separated) in filenames. diff --git a/DIRECTORY.md b/DIRECTORY.md index 6b744c8c8..fa7b669ce 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -19,6 +19,7 @@ * [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp) ## Ciphers + * [Atbash Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/atbash_cipher.cpp) * [Base64 Encoding](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/base64_encoding.cpp) * [Caesar Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/caesar_cipher.cpp) * [Elliptic Curve Key Exchange](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/elliptic_curve_key_exchange.cpp) @@ -242,6 +243,7 @@ * [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp) * [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp) * [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp) + * [Reverse Binary Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_binary_tree.cpp) * [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp) * [Trie Multiple Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/trie_multiple_search.cpp) * [Union Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/union_of_2_arrays.cpp) diff --git a/ciphers/atbash_cipher.cpp b/ciphers/atbash_cipher.cpp new file mode 100644 index 000000000..04c330598 --- /dev/null +++ b/ciphers/atbash_cipher.cpp @@ -0,0 +1,83 @@ +/** + * @file + * @brief [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + * @details The Atbash cipher is a subsitution cipher where the letters of the + * alphabet are in reverse. For example, A is replaced with Z, B is replaced + * with Y, etc. + * + * ### Algorithm + * The algorithm takes a string, and looks up the corresponding reversed letter + * for each letter in the word and replaces it. Spaces are ignored and case is + * preserved. + * + * @author [Focusucof](https://github.com/Focusucof) + */ +#include /// for assert +#include /// for IO operations +#include /// for std::map +#include /// for std::string + +/** \namespace ciphers + * \brief Algorithms for encryption and decryption + */ +namespace ciphers { +/** \namespace atbash + * \brief Functions for the [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation + */ +namespace atbash { +std::map atbash_cipher_map = { + {'a', 'z'}, {'b', 'y'}, {'c', 'x'}, {'d', 'w'}, {'e', 'v'}, {'f', 'u'}, + {'g', 't'}, {'h', 's'}, {'i', 'r'}, {'j', 'q'}, {'k', 'p'}, {'l', 'o'}, + {'m', 'n'}, {'n', 'm'}, {'o', 'l'}, {'p', 'k'}, {'q', 'j'}, {'r', 'i'}, + {'s', 'h'}, {'t', 'g'}, {'u', 'f'}, {'v', 'e'}, {'w', 'd'}, {'x', 'c'}, + {'y', 'b'}, {'z', 'a'}, {'A', 'Z'}, {'B', 'Y'}, {'C', 'X'}, {'D', 'W'}, + {'E', 'V'}, {'F', 'U'}, {'G', 'T'}, {'H', 'S'}, {'I', 'R'}, {'J', 'Q'}, + {'K', 'P'}, {'L', 'O'}, {'M', 'N'}, {'N', 'M'}, {'O', 'L'}, {'P', 'K'}, + {'Q', 'J'}, {'R', 'I'}, {'S', 'H'}, {'T', 'G'}, {'U', 'F'}, {'V', 'E'}, + {'W', 'D'}, {'X', 'C'}, {'Y', 'B'}, {'Z', 'A'}, {' ', ' '} + +}; + +/** + * @brief atbash cipher encryption and decryption + * @param text Plaintext to be encrypted + * @returns encoded or decoded string + */ +std::string atbash_cipher(std::string text) { + std::string result; + for (char letter : text) { + result += atbash_cipher_map[letter]; + } + return result; +} + +} // namespace atbash +} // namespace ciphers + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::string text = "Hello World"; + std::string expected = "Svool Dliow"; + std::string encrypted_text = ciphers::atbash::atbash_cipher(text); + std::string decrypted_text = ciphers::atbash::atbash_cipher(encrypted_text); + assert(expected == encrypted_text); + assert(text == decrypted_text); + std::cout << "Original text: " << text << std::endl; + std::cout << ", Expected text: " << expected << std::endl; + std::cout << ", Encrypted text: " << encrypted_text << std::endl; + std::cout << ", Decrypted text: " << decrypted_text << std::endl; + std::cout << "\nAll tests have successfully passed!\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/operations_on_datastructures/reverse_binary_tree.cpp b/operations_on_datastructures/reverse_binary_tree.cpp new file mode 100644 index 000000000..46b742efc --- /dev/null +++ b/operations_on_datastructures/reverse_binary_tree.cpp @@ -0,0 +1,255 @@ +/** + * @file + * @brief Implementation for the [Reversing a Binary + * Tree](https://www.geeksforgeeks.org/reverse-tree-path/) recursively + * algorithm. + * @details A binary tree can be reversed by swapping the left and + * right child of a node at each node, starting from the root, and + * cascading below. This solution aims to provide an implementation of + * a recursive reversal of a binary tree. + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// For assert +#include /// For IO operations +#include /// For std::queue +#include /// For std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @namespace reverse_binary_tree + * @brief Functions for the [Reverse a Binary + * Tree](https://www.geeksforgeeks.org/reverse-tree-path/) implementation + */ +namespace reverse_binary_tree { + +/** + * @brief A Node struct that represents a single node in a Binary Tree + */ +struct Node { + int64_t data; ///< The value of the Node + Node* left; ///< The Node's left child + Node* right; ///< The Node's right child + /** + * @brief Creates a new Node with some initial data + */ + explicit Node(int64_t _data) { + data = _data; ///< Set value of Node data + left = nullptr; ///< Initialize left child to NULL + right = nullptr; ///< Initialize right child to NULL + } +}; + +/** + * @brief A Binary Tree class that implements a Binary Search Tree + *(BST) by default. + */ +class BinaryTree { + private: + Node* root; ///< Pointer to root node of Binary Tree + /** + * @brief inserts a node in the Binary Tree, with the behaviouur of + * a Binary Search Tree. + * @details Nodes with smaller values are inserted in the left + * subtree, and Nodes with larger values are inserted into the + * right subtree recursively. Time Complexity: O(log(n)) + * @param data The data/value of the Node to be inserted + * @param pivot A pointer to the root node of the (sub)tree + * @returns Node pointer to the root + */ + Node* insert(int64_t data, Node* pivot) { + if (pivot == nullptr) { + return new Node(data); ///< Create new node + } + if (data <= pivot->data) { + pivot->left = + insert(data, pivot->left); ///< Insert Node to the left + } else { + pivot->right = + insert(data, pivot->right); ///< Insert node to the right + } + return pivot; + } + /** + * @brief Reverses a Binary Tree recursively by swapping the left and + * right subtrees and their children. + * @param pivot A reference to the root of the (sub)tree + * @returns Node pointer to root node + */ + Node* reverseBinaryTree(Node* pivot) { + if (pivot == nullptr) { + return pivot; ///< Base case + } + Node* temp = pivot->left; ///< pointer to the left subtree + pivot->left = reverseBinaryTree(pivot->right); ///< Swap + pivot->right = reverseBinaryTree(temp); ///< Swap + return pivot; + } + + public: + /** + * @brief Creates a BinaryTree with a root pointing to NULL. + */ + BinaryTree() { root = nullptr; } + /** + * @brief Creates a BinaryTree with a root with an initial value. + */ + explicit BinaryTree(int64_t data) { root = new Node(data); } + /** + * @brief Adds a new Node to the Binary Tree + */ + void add(int64_t data) { root = insert(data, root); } + /** + * Reverses the Binary Tree + */ + void reverse() { root = reverseBinaryTree(root); } + /** + * @brief Level order traversal of a tree consists of visiting its + * elements, top to bottom, left to right. This function performs + * level order traversal and returns the node datas as a vector. + * @details The function uses a queue to append and remove elements + * as they are visited, and then adds their children, if any. This + * ensures that the elements are visited layer-by-layer, starting + * from the root of the Tree. + * @returns vector of nodes of the tree. + */ + std::vector get_level_order() { + std::vector data; ///< Result vector of int + if (root == nullptr) { + return data; ///< Return empty vector if root is Invalid + } + std::queue nodes; ///< Queue of the nodes in the tree + nodes.push(root); ///< Insert root into the queue + while (!nodes.empty()) { + Node* temp = nodes.front(); ///< Copy the first element + data.push_back(temp->data); ///< Add the element to the data + nodes.pop(); ///< Remove element + if (temp->left != nullptr) { + nodes.push(temp->left); ///< Insert left node + } + if (temp->right != nullptr) { + nodes.push(temp->right); ///< Insert right node + } + } /// Add nodes while Tree is not empty + return data; + } + /** + * @brief Prints all of the elements in the tree to stdout + * level-by-level, using the get_level_order() function. + * @returns void + */ + void print() { + for (int i : get_level_order()) { + std::cout << i << " "; /// Print each element in the tree + } + std::cout << "\n"; /// Print newline + } +}; + +} // namespace reverse_binary_tree +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check Reversal of Binary Tree. + */ +namespace tests { +using operations_on_datastructures::reverse_binary_tree:: + BinaryTree; ///< Use the BinaryTree +/** + * @brief A Test to check an edge case (single element reversal) + */ +void test1() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::cout << "TEST CASE 1\n"; + std::cout << "Initializing tree with a single element (5)\n"; + bst.add(5); + pre_reversal = bst.get_level_order(); + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(pre_reversal.size() == + post_reversal.size()); ///< Check for equal sizes + assert(pre_reversal.size() == + 1); ///< Ensure that there is only one element + assert(pre_reversal[0] == + post_reversal[0]); ///< Check if both elements are same + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an edge case (NULL root element) + */ +void test2() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::cout << "TEST CASE 2\n"; + std::cout << "Creating empty tree (root points to NULL)\n"; + pre_reversal = bst.get_level_order(); + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(pre_reversal.size() == + post_reversal.size()); ///< Check for equal sizes + assert(pre_reversal.size() == + 0); ///< Ensure that there is only one element + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct reversal of a Binary Tree + */ +void test3() { + BinaryTree bst; + std::vector pre_reversal, post_reversal; + std::vector pre_res = {4, 3, 6, 2, 5, 7, 1}; + std::vector post_res = {4, 6, 3, 7, 5, 2, 1}; + std::cout << "TEST CASE 3\n"; + std::cout << "Creating tree with elements (4, 6, 3, 2, 5, 7, 1)\n"; + bst.add(4); + bst.add(6); + bst.add(3); + bst.add(2); + bst.add(5); + bst.add(7); + bst.add(1); + pre_reversal = bst.get_level_order(); + assert(pre_reversal == pre_res); ///< Check for equality + std::cout << "Before reversal: "; + bst.print(); + std::cout << "After reversal: "; + bst.reverse(); + post_reversal = bst.get_level_order(); + assert(post_reversal == post_res); ///< Check for equality + bst.print(); + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of the Tree Reversal + */ +static void test() { + tests::test1(); ///< Single element test + tests::test2(); ///< No element test + tests::test3(); ///< Correct reversal test +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +}