diff --git a/DIRECTORY.md b/DIRECTORY.md index 9e36309dc..f8ad585d5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -49,6 +49,7 @@ * [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/stk/stack.h) * [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/stk/test_stack.cpp) * [Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/Tree.cpp) + * [Trie Modern](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/trie_modern.cpp) * [Trie Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structure/trie_tree.cpp) ## Dynamic Programming @@ -72,6 +73,9 @@ * [Searching Of Element In Dynamic Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/searching_of_element_in_dynamic_array.cpp) * [Tree Height](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/tree_height.cpp) +## Geometry + * [Line Segment Intersection](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/line_segment_intersection.cpp) + ## Graph * [Bfs](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/BFS.cpp) * [Bridge Finding With Tarjan Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/bridge_finding_with_tarjan_algorithm.cpp) @@ -111,6 +115,7 @@ * [Fibonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/fibonacci.cpp) * [Greatest Common Divisor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/greatest_common_divisor.cpp) * [Greatest Common Divisor Euclidean](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/greatest_common_divisor_euclidean.cpp) + * [Least Common Multiple](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/least_common_multiple.cpp) * [Modular Inverse Fermat Little Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_inverse_fermat_little_theorem.cpp) * [Number Of Positive Divisors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/number_of_positive_divisors.cpp) * [Power For Huge Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/power_for_huge_numbers.cpp) @@ -196,7 +201,7 @@ * [Non Recursive Merge Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/non_recursive_merge_sort.cpp) * [Numericstringsort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/NumericStringSort.cpp) * [Oddeven Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/OddEven%20Sort.cpp) - * [Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/Quick%20Sort.cpp) + * [Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort.cpp) * [Radix Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/Radix%20Sort.cpp) * [Selection Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/Selection%20Sort.cpp) * [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/Shell%20Sort.cpp) diff --git a/data_structure/trie_modern.cpp b/data_structure/trie_modern.cpp new file mode 100644 index 000000000..218c90b68 --- /dev/null +++ b/data_structure/trie_modern.cpp @@ -0,0 +1,167 @@ +/** + * Copyright 2020 @author Anmol3299 + * @file + * + * A basic implementation of trie class to store only lower-case strings. + */ +#include // for io operations +#include // for std::shared_ptr<> +#include // for std::string class + +/** + * A basic implementation of trie class to store only lower-case strings. + * You can extend the implementation to all the ASCII characters by changing the + * value of @ ALPHABETS to 128. + */ +class Trie { + private: + static constexpr size_t ALPHABETS = 26; + + /** + * Structure of trie node. + * This struct doesn't need a constructor as we are initializing using + * intializer list which is more efficient than if we had done so with + * constructor. + */ + struct TrieNode { + // An array of pointers of size 26 which tells if a character of word is + // present or not. + std::shared_ptr character[ALPHABETS]{nullptr}; + + bool isEndOfWord{false}; + }; + + /** + * Function to check if a node has some children which can form words. + * @param node whose character array of pointers need to be checked for + * children. + * @return if a child is found, it returns @ true, else it returns @ false. + */ + inline static bool hasChildren(std::shared_ptr node) { + for (size_t i = 0; i < ALPHABETS; i++) { + if (node->character[i]) { + return true; + } + } + return false; + } + + /** + * A recursive helper function to remove a word from the trie. First, it + * recursively traverses to the location of last character of word in the + * trie. However, if the word is not found, the function returns a runtime + * error. Upon successfully reaching the last character of word in trie, if + * sets the isEndOfWord to false and deletes the node if and only if it has + * no children, else it returns the current node. + * @param word is the string which needs to be removed from trie. + * @param curr is the current node we are at. + * @param index is the index of the @word we are at. + * @return if current node has childern, it returns @ curr, else it returns + * nullptr. + * @throw a runtime error in case @ word is not found in the trie. + */ + std::shared_ptr removeWordHelper(const std::string& word, + std::shared_ptr curr, + size_t index) { + if (word.size() == index) { + if (curr->isEndOfWord) { + curr->isEndOfWord = false; + } + if (hasChildren(curr)) { + return curr; + } + return nullptr; + } + + size_t idx = word[index] - 'a'; + + // Throw a runtime error in case the user enters a word which is not + // present in the trie. + if (!curr->character[idx]) { + throw std::runtime_error(std::move(std::string("Word not found."))); + } + + curr->character[idx] = + removeWordHelper(word, curr->character[idx], index + 1); + + // This if condition checks if the node has some childern. + // The 1st if check, i.e. (curr->character[idx]) is checked specifically + // because if the older string is a prefix of some other string, then, + // there would be no need to check all 26 characters. Example- str1 = + // abbey, str2 = abbex and we want to delete string "abbey", then in + // this case, there would be no need to check all characters for the + // chars a,b,b. + if (curr->character[idx] || hasChildren(curr)) { + return curr; + } + return nullptr; + } + + public: + // constructor to initialise the root of the trie. + Trie() : m_root(std::make_shared()) {} + + /** + * Insert a word into the trie. + * @param word which needs to be inserted into the string. + */ + void insert(const std::string& word) { + auto curr = m_root; + for (char ch : word) { + size_t index = ch - 'a'; + + // if a node for current word is not already present in trie, create + // a new node for it. + if (!curr->character[index]) { + curr->character[index] = std::make_shared(); + } + + curr = curr->character[index]; + } + curr->isEndOfWord = true; + } + + /** + * Search if a word is present in trie or not. + * @param word which is needed to be searched in the trie. + * @return True if the word is found in trie and isEndOfWord is set to true. + * @return False if word is not found in trie or isEndOfWord is set to + * false. + */ + bool search(const std::string& word) { + auto curr = m_root; + for (char ch : word) { + size_t index = ch - 'a'; + + // if any node for a character is not found, then return that the + // word cannot be formed. + if (!curr->character[index]) { + return false; + } + curr = curr->character[index]; + } + return curr->isEndOfWord; + } + + // Function to remove the word which calls the helper function. + void removeWord(const std::string& word) { + m_root = removeWordHelper(word, m_root, 0); + } + + private: + // data member to store the root of the trie. + std::shared_ptr m_root; +}; + +/** + * Main function + */ +int main() { + Trie trie; + trie.insert("hel"); + trie.insert("hello"); + trie.removeWord("hel"); + std::cout << trie.search("hello") << '\n'; + + return 0; +} diff --git a/geometry/line_segment_intersection.cpp b/geometry/line_segment_intersection.cpp new file mode 100644 index 000000000..0b5b858d7 --- /dev/null +++ b/geometry/line_segment_intersection.cpp @@ -0,0 +1,101 @@ +/** + * @file + * @brief check whether two line segments intersect each other + * or not. + */ +#include + +/** + * Define a Point. + */ +struct Point { + int x; /// Point respect to x coordinate + int y; /// Point respect to y coordinate +}; + +/** + * intersect returns true if segments of two line intersects and + * false if they do not. It calls the subroutines direction + * which computes the orientation. + */ +struct SegmentIntersection { + inline bool intersect(Point first_point, Point second_point, + Point third_point, Point forth_point) { + int direction1 = direction(third_point, forth_point, first_point); + int direction2 = direction(third_point, forth_point, second_point); + int direction3 = direction(first_point, second_point, third_point); + int direction4 = direction(first_point, second_point, forth_point); + + if ((direction1 < 0 || direction2 > 0) && (direction3 < 0 || + direction4 > 0)) + return true; + + else if (direction1 == 0 && on_segment(third_point, forth_point, + first_point)) + return true; + + else if (direction2 == 0 && on_segment(third_point, forth_point, + second_point)) + return true; + + else if (direction3 == 0 && on_segment(first_point, second_point, + third_point)) + return true; + + else if (direction3 == 0 && on_segment(first_point, second_point, + forth_point)) + return true; + + else + return false; + } + + /** + * We will find direction of line here respect to @first_point. + * Here @second_point and @third_point is first and second points + * of the line respectively. we want a method to determine which way a + * given angle these three points turns. If returned number is negative, + * then the angle is counter-clockwise. That means the line is going to + * right to left. We will fount angle as clockwise if the method returns + * positive number. + */ + inline int direction(Point first_point, Point second_point, + Point third_point) { + return ((third_point.x-first_point.x)*(second_point.y-first_point.y))- + ((second_point.x-first_point.x) * (third_point.y-first_point.y)); + } + + /** + * This method determines whether a point known to be colinear + * with a segment lies on that segment. + */ + inline bool on_segment(Point first_point, Point second_point, + Point third_point) { + if (std::min(first_point.x, second_point.x) <= third_point.x && + third_point.x <= std::max(first_point.x, second_point.x) && + std::min(first_point.y, second_point.y) <= third_point.y && + third_point.y <= std::max(first_point.y, second_point.y)) + return true; + + else + return false; + } +}; + +/** + * This is the main function to test whether the algorithm is + * working well. + */ +int main() { + SegmentIntersection segment; + Point first_point, second_point, third_point, forth_point; + + std::cin >> first_point.x >> first_point.y; + std::cin >> second_point.x >> second_point.y; + std::cin >> third_point.x >> third_point.y; + std::cin >> forth_point.x >> forth_point.y; + + printf("%d", segment.intersect(first_point, second_point, third_point, + forth_point)); + std::cout << std::endl; +} diff --git a/math/least_common_multiple.cpp b/math/least_common_multiple.cpp new file mode 100644 index 000000000..741945716 --- /dev/null +++ b/math/least_common_multiple.cpp @@ -0,0 +1,70 @@ +/** + * Copyright 2020 @author tjgurwara99 + * @file + * + * A basic implementation of LCM function + */ + +#include +#include + +/** + * Function for finding greatest common divisor of two numbers. + * @params two integers x and y whose gcd we want to find. + * @return greatest common divisor of x and y. + */ +unsigned int gcd(unsigned int x, unsigned int y) { + if (x == 0) { + return y; + } + if (y == 0) { + return x; + } + if (x == y) { + return x; + } + if (x > y) { + // The following is valid because we have checked whether y == 0 + + int temp = x / y; + return gcd(y, x - temp * y); + } + // Again the following is valid because we have checked whether x == 0 + + int temp = y / x; + return gcd(x, y - temp * x); +} + +/** + * Function for finding the least common multiple of two numbers. + * @params integer x and y whose lcm we want to find. + * @return lcm of x and y using the relation x * y = gcd(x, y) * lcm(x, y) + */ +unsigned int lcm(unsigned int x, unsigned int y) { return x * y / gcd(x, y); } + +/** + * Function for testing the lcm() functions with some assert statements. + */ +void tests() { + // First test on lcm(5,10) == 10 + assert(((void)"LCM of 5 and 10 is 10 but lcm function gives a different " + "result.\n", + lcm(5, 10) == 10)); + std::cout << "First assertion passes: LCM of 5 and 10 is " << lcm(5, 10) + << std::endl; + + // Second test on lcm(2,3) == 6 as 2 and 3 are coprime (prime in fact) + assert(((void)"LCM of 2 and 3 is 6 but lcm function gives a different " + "result.\n", + lcm(2, 3) == 6)); + std::cout << "Second assertion passes: LCM of 2 and 3 is " << lcm(2, 3) + << std::endl; +} + +/** + * Main function + */ +int main() { + tests(); + return 0; +}