-
- Notifications
You must be signed in to change notification settings - Fork 7.7k
feat: Trie data structure using hashmap, predict_words method, class Trie #1464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
11 commits Select commit Hold shift + click to select a range
1f7faeb feat: add Trie data structure using hashmap, predict_words method, cl…
bharath000 235e080 updating DIRECTORY.md
c8585c9 fix: fixed clang.tidy warnings
bharath000 3e5b163 docs: added documentation toclass trie
bharath000 9031f4e docs: updated documentation
bharath000 494b97f fix: added namespace trie_using_hashmap
bharath000 03894a2 docs: updated documentation with comments
bharath000 99416ab docs: updated documentation with spelling corrections
bharath000 1799662 docs: updated requested changes
bharath000 b0b6e2a docs : updated requested changes in documentation
bharath000 7f45339 fix: Apply suggestions from code review
Panquesito7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,337 @@ | ||
| /** | ||
| * @file | ||
| * @author [Venkata Bharath](https://github.com/bharath000) | ||
| * @brief Implementation of [Trie](https://en.wikipedia.org/wiki/Trie) data | ||
| * structure using HashMap for different characters and method for predicting | ||
| * words based on prefix. | ||
| * @details The Trie data structure is implemented using unordered map to use | ||
| * memory optimally, predict_words method is developed to recommend words based | ||
| * on a given prefix along with other methods insert, delete, search, startwith | ||
| * in trie. | ||
| * @see trie_modern.cpp for difference | ||
| */ | ||
| #include <cassert> /// for assert | ||
| #include <iostream> /// for IO operations | ||
| #include <memory> /// for std::shared_ptr | ||
| #include <stack> /// for std::stack | ||
| #include <unordered_map> /// for std::unordered_map | ||
| #include <vector> /// for std::vector | ||
| | ||
| /** | ||
| * @namespace data_structures | ||
| * @brief Data structures algorithms | ||
| */ | ||
| namespace data_structures { | ||
ayaankhan98 marked this conversation as resolved. Show resolved Hide resolved | ||
| | ||
| /** | ||
| * @brief Trie class. implementation of trie using hashmap in each trie node for | ||
| * all the charters of char16_t(UTF-16)type with methods to insert, delete, | ||
| * search, start with, and to recommend words based on a given prefix. | ||
| */ | ||
| class Trie { | ||
| private: | ||
| /** | ||
| * @brief struct representing nodes in the trie | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| */ | ||
| struct Node { | ||
| std::unordered_map<char16_t, std::shared_ptr<Node>> | ||
| children; /// unordered map with key type char16_t and value is a | ||
| /// shared pointer type of Node | ||
| bool word_end = false; /// boolean variable to represent the node end | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| }; | ||
| | ||
| std::shared_ptr<Node> root_node = | ||
| std::make_shared<Node>(); ///< declaring root node of trie | ||
| | ||
| public: | ||
| ///< Constructor | ||
| Trie() = default; | ||
| | ||
| /** | ||
| * @brief insert the string into the trie | ||
| * @param word string to insert in the tree | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| */ | ||
| void insert(const std::string& word) { | ||
| std::shared_ptr<Node> curr = root_node; | ||
| for (char ch : word) { | ||
| if (curr->children.find(ch) == curr->children.end()) { | ||
| curr->children[ch] = std::make_shared<Node>(); | ||
| } | ||
| curr = curr->children[ch]; | ||
| } | ||
| | ||
| if (!curr->word_end && curr != root_node) { | ||
| curr->word_end = true; | ||
| } | ||
| } | ||
| | ||
| /** | ||
| * @brief search a word/string exists inside the trie | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| * @param word string to search for | ||
| * @returns `true` if found | ||
| * @returns `false` if not found | ||
| */ | ||
| bool search(const std::string& word) { | ||
| std::shared_ptr<Node> curr = root_node; | ||
| for (char ch : word) { | ||
| if (curr->children.find(ch) == curr->children.end()) { | ||
| return false; | ||
| } | ||
| curr = curr->children[ch]; | ||
| if (!curr) { | ||
| return false; | ||
| } | ||
| } | ||
| | ||
| if (curr->word_end) { | ||
| return true; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
| | ||
| /** | ||
| * @brief search a word/string that starts with a given prefix | ||
| * @param prefix string to search for | ||
| * @returns `true` if found | ||
| * @returns `false` if not found | ||
| */ | ||
| bool startwith(const std::string& prefix) { | ||
| std::shared_ptr<Node> curr = root_node; | ||
| for (char ch : prefix) { | ||
| if (curr->children.find(ch) == curr->children.end()) { | ||
| return false; | ||
| } | ||
| curr = curr->children[ch]; | ||
| } | ||
| return true; | ||
| } | ||
| | ||
| /** | ||
| * @brief delete a word/string from a trie | ||
| * @param word string to delete fromm trie | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| */ | ||
| void delete_word(std::string word) { | ||
| std::shared_ptr<Node> curr = root_node; | ||
| std::stack<std::shared_ptr<Node>> nodes; | ||
| int cnt = 0; | ||
| for (char ch : word) { | ||
| if (curr->children.find(ch) == curr->children.end()) { | ||
| return; | ||
| } | ||
| if (curr->word_end) { | ||
| cnt++; | ||
| } | ||
| | ||
| nodes.push(curr->children[ch]); | ||
| curr = curr->children[ch]; | ||
| } | ||
| /*delete only when its a word and it has no children after and also no | ||
| * prefix in the line*/ | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| if (nodes.top()->word_end) { | ||
| nodes.top()->word_end = false; | ||
| } | ||
| while (!(nodes.top()->word_end) && nodes.top()->children.empty()) { | ||
| /* code */ | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| nodes.pop(); | ||
| nodes.top()->children.erase(word.back()); | ||
| word.pop_back(); | ||
| } | ||
| } | ||
| | ||
| /** | ||
| * @brief helper function to predict/recommend words that starts with a | ||
| * given prefix from the end of prefix's node iterate through all the child | ||
| * nodes by recursively appending all the possible words below the trie | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| * @param prefix string to recommend the words | ||
| * @param element node at the end of given prefix | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| * @param results list to store the all possible words | ||
| * @returns list of recommended words | ||
| */ | ||
| std::vector<std::string> get_all_words(std::vector<std::string> results, | ||
| const std::shared_ptr<Node>& element, | ||
| std::string prefix) { | ||
| if (element->word_end) { | ||
| results.push_back(prefix); | ||
| } | ||
| if (element->children.empty()) { | ||
| return results; | ||
| } | ||
| for (auto const& x : element->children) { | ||
| std::string key = ""; | ||
| key = x.first; | ||
| prefix += key; | ||
| | ||
| results = | ||
| get_all_words(results, element->children[x.first], prefix); | ||
| | ||
| prefix.pop_back(); | ||
| } | ||
| | ||
| return results; | ||
| } | ||
| | ||
| /** | ||
| * @brief predict/recommend a words that starts with a given prefix | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| * @param prefix string to search for | ||
| * @returns list of recommended words | ||
| */ | ||
| std::vector<std::string> predict_words(const std::string& prefix) { | ||
| std::vector<std::string> result; | ||
| std::shared_ptr<Node> curr = root_node; | ||
| /* treversing till the end of given prefix in trie*/ | ||
| | ||
| for (char ch : prefix) { | ||
| if (curr->children.find(ch) == curr->children.end()) { | ||
| return result; | ||
| } | ||
| | ||
| curr = curr->children[ch]; | ||
| } | ||
| | ||
| /* if given prefix is the only word without children */ | ||
| if (curr->word_end && curr->children.empty()) { | ||
| result.push_back(prefix); | ||
| return result; | ||
| } | ||
| | ||
| result = get_all_words( | ||
| result, curr, | ||
| prefix); ///< iteratively and recursively get the recommended words | ||
| | ||
| return result; | ||
| } | ||
| }; | ||
| | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| } // namespace data_structures | ||
| | ||
| /** | ||
| * @brief Self-test implementations | ||
| * @returns void | ||
| */ | ||
| static void test() { | ||
| data_structures::Trie obj; | ||
Panquesito7 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| /* Inserting data into trie using insert method and testing it with search | ||
| * method */ | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| obj.insert("app"); | ||
| obj.insert("abscond"); | ||
| obj.insert("about"); | ||
| obj.insert("apps"); | ||
| obj.insert("apen"); | ||
| obj.insert("apples"); | ||
| obj.insert("apple"); | ||
| obj.insert("approach"); | ||
| obj.insert("bus"); | ||
| obj.insert("buses"); | ||
| obj.insert("Apple"); | ||
| obj.insert("Bounce"); | ||
| | ||
| assert(!obj.search("appy")); | ||
| std::cout << "appy is not a word in trie" << std::endl; | ||
| | ||
| assert(!obj.search("car")); | ||
| std::cout << "car is not a word in trie" << std::endl; | ||
| assert(obj.search("app")); | ||
| assert(obj.search("apple")); | ||
| assert(obj.search("apples")); | ||
| assert(obj.search("apps")); | ||
| assert(obj.search("apen")); | ||
| assert(obj.search("approach")); | ||
| assert(obj.search("about")); | ||
| assert(obj.search("abscond")); | ||
| assert(obj.search("bus")); | ||
| assert(obj.search("buses")); | ||
| assert(obj.search("Bounce")); | ||
| assert(obj.search("Apple")); | ||
| | ||
| std::cout << "All the Inserted words are present in the trie" << std::endl; | ||
| | ||
| // test for startwith prefix method | ||
| assert(!obj.startwith("approachs")); | ||
| assert(obj.startwith("approach")); | ||
| assert(obj.startwith("about")); | ||
| assert(!obj.startwith("appy")); | ||
| assert(obj.startwith("abscond")); | ||
| assert(obj.startwith("bus")); | ||
| assert(obj.startwith("buses")); | ||
| assert(obj.startwith("Bounce")); | ||
| assert(obj.startwith("Apple")); | ||
| assert(obj.startwith("abs")); | ||
| assert(obj.startwith("b")); | ||
| assert(obj.startwith("bus")); | ||
| assert(obj.startwith("Bo")); | ||
| assert(obj.startwith("A")); | ||
| assert(!obj.startwith("Ca")); | ||
| | ||
| assert(!obj.startwith("C")); | ||
| | ||
| std::cout << "All the tests passed for startwith method" << std::endl; | ||
| | ||
| // test for predict_words/recommendation of words based on a given prefix | ||
| | ||
| std::vector<std::string> pred_words = obj.predict_words("a"); | ||
| | ||
| for (const std::string& str : obj.predict_words("a")) { | ||
| std::cout << str << std::endl; | ||
| } | ||
| assert(pred_words.size() == 8); | ||
| std::cout << "Returned all words that start with prefix a " << std::endl; | ||
| pred_words = obj.predict_words("app"); | ||
| | ||
| for (const std::string& str : pred_words) { | ||
| std::cout << str << std::endl; | ||
| } | ||
| | ||
| assert(pred_words.size() == 5); | ||
| std::cout << "Returned all words that start with prefix app " << std::endl; | ||
| pred_words = obj.predict_words("A"); | ||
| | ||
| for (const std::string& str : pred_words) { | ||
| std::cout << str << std::endl; | ||
| } | ||
| | ||
| assert(pred_words.size() == 1); | ||
| std::cout << "Returned all words that start with prefix A " << std::endl; | ||
| pred_words = obj.predict_words("bu"); | ||
| | ||
| for (const std::string& str : pred_words) { | ||
| std::cout << str << std::endl; | ||
| } | ||
| | ||
| assert(pred_words.size() == 2); | ||
| std::cout << "Returned all words that start with prefix bu " << std::endl; | ||
| | ||
| // tests for delete method | ||
| | ||
| obj.delete_word("app"); | ||
| assert(!obj.search("app")); | ||
| std::cout << "word app is deleted sucessful" << std::endl; | ||
| | ||
| pred_words = obj.predict_words("app"); | ||
| for (const std::string& str : pred_words) { | ||
| std::cout << str << std::endl; | ||
| } | ||
| assert(pred_words.size() == 4); | ||
| std::cout << "app is deleted sucessful" << std::endl; | ||
| | ||
| // test case for Chinese language | ||
| | ||
| obj.insert("苹果"); | ||
| assert(obj.startwith("苹")); | ||
| pred_words = obj.predict_words("h"); | ||
| | ||
| assert(pred_words.size() == 0); | ||
| std::cout << "No word starts with prefix h in trie" << std::endl; | ||
| | ||
| std::cout << "All tests passed" << std::endl; | ||
| } | ||
| | ||
| /** | ||
| * @brief Main function | ||
| * @returns 0 on exit | ||
| */ | ||
| int main() { | ||
| test(); // run self-test implementaions | ||
| | ||
bharath000 marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| return 0; | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.