TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
trie_using_hashmap.cpp
Go to the documentation of this file.
1
13#include <cassert>
14#include <iostream>
15#include <memory>
16#include <stack>
17#include <unordered_map>
18#include <vector>
19
24namespace data_structures {
25
31namespace trie_using_hashmap {
32
39class Trie {
40 private:
44 struct Node {
45 std::unordered_map<char16_t, std::shared_ptr<Node>>
48 bool word_end = false;
49 };
50
51 std::shared_ptr<Node> root_node =
52 std::make_shared<Node>();
53
54 public:
56 Trie() = default;
57
62 void insert(const std::string& word) {
63 std::shared_ptr<Node> curr = root_node;
64 for (char ch : word) {
65 if (curr->children.find(ch) == curr->children.end()) {
66 curr->children[ch] = std::make_shared<Node>();
67 }
68 curr = curr->children[ch];
69 }
70
71 if (!curr->word_end && curr != root_node) {
72 curr->word_end = true;
73 }
74 }
75
82 bool search(const std::string& word) {
83 std::shared_ptr<Node> curr = root_node;
84 for (char ch : word) {
85 if (curr->children.find(ch) == curr->children.end()) {
86 return false;
87 }
88 curr = curr->children[ch];
89 if (!curr) {
90 return false;
91 }
92 }
93
94 if (curr->word_end) {
95 return true;
96 } else {
97 return false;
98 }
99 }
100
107 bool startwith(const std::string& prefix) {
108 std::shared_ptr<Node> curr = root_node;
109 for (char ch : prefix) {
110 if (curr->children.find(ch) == curr->children.end()) {
111 return false;
112 }
113 curr = curr->children[ch];
114 }
115 return true;
116 }
117
122 void delete_word(std::string word) {
123 std::shared_ptr<Node> curr = root_node;
124 std::stack<std::shared_ptr<Node>> nodes;
125 int cnt = 0;
126 for (char ch : word) {
127 if (curr->children.find(ch) == curr->children.end()) {
128 return;
129 }
130 if (curr->word_end) {
131 cnt++;
132 }
133
134 nodes.push(curr->children[ch]);
135 curr = curr->children[ch];
136 }
137 // Delete only when it's a word, and it has children after
138 // or prefix in the line
139 if (nodes.top()->word_end) {
140 nodes.top()->word_end = false;
141 }
142 // Delete only when it has no children after
143 // and also no prefix in the line
144 while (!(nodes.top()->word_end) && nodes.top()->children.empty()) {
145 nodes.pop();
146 nodes.top()->children.erase(word.back());
147 word.pop_back();
148 }
149 }
150
160 std::vector<std::string> get_all_words(std::vector<std::string> results,
161 const std::shared_ptr<Node>& element,
162 std::string prefix) {
163 if (element->word_end) {
164 results.push_back(prefix);
165 }
166 if (element->children.empty()) {
167 return results;
168 }
169 for (auto const& x : element->children) {
170 std::string key = "";
171 key = x.first;
172 prefix += key;
173
174 results =
175 get_all_words(results, element->children[x.first], prefix);
176
177 prefix.pop_back();
178 }
179
180 return results;
181 }
182
188 std::vector<std::string> predict_words(const std::string& prefix) {
189 std::vector<std::string> result;
190 std::shared_ptr<Node> curr = root_node;
191 // traversing until the end of the given prefix in trie
192
193 for (char ch : prefix) {
194 if (curr->children.find(ch) == curr->children.end()) {
195 return result;
196 }
197
198 curr = curr->children[ch];
199 }
200
201 // if the given prefix is the only word without children
202 if (curr->word_end && curr->children.empty()) {
203 result.push_back(prefix);
204 return result;
205 }
206
207 result = get_all_words(
208 result, curr,
209 prefix);
210
211 return result;
212 }
213};
214} // namespace trie_using_hashmap
215} // namespace data_structures
216
221static void test() {
223 // Inserting data into trie using the insert
224 // method and testing it with search method
225 obj.insert("app");
226 obj.insert("abscond");
227 obj.insert("about");
228 obj.insert("apps");
229 obj.insert("apen");
230 obj.insert("apples");
231 obj.insert("apple");
232 obj.insert("approach");
233 obj.insert("bus");
234 obj.insert("buses");
235 obj.insert("Apple");
236 obj.insert("Bounce");
237
238 assert(!obj.search("appy"));
239 std::cout << "appy is not a word in trie" << std::endl;
240
241 assert(!obj.search("car"));
242 std::cout << "car is not a word in trie" << std::endl;
243 assert(obj.search("app"));
244 assert(obj.search("apple"));
245 assert(obj.search("apples"));
246 assert(obj.search("apps"));
247 assert(obj.search("apen"));
248 assert(obj.search("approach"));
249 assert(obj.search("about"));
250 assert(obj.search("abscond"));
251 assert(obj.search("bus"));
252 assert(obj.search("buses"));
253 assert(obj.search("Bounce"));
254 assert(obj.search("Apple"));
255
256 std::cout << "All the Inserted words are present in the trie" << std::endl;
257
258 // test for startwith prefix method
259 assert(!obj.startwith("approachs"));
260 assert(obj.startwith("approach"));
261 assert(obj.startwith("about"));
262 assert(!obj.startwith("appy"));
263 assert(obj.startwith("abscond"));
264 assert(obj.startwith("bus"));
265 assert(obj.startwith("buses"));
266 assert(obj.startwith("Bounce"));
267 assert(obj.startwith("Apple"));
268 assert(obj.startwith("abs"));
269 assert(obj.startwith("b"));
270 assert(obj.startwith("bus"));
271 assert(obj.startwith("Bo"));
272 assert(obj.startwith("A"));
273 assert(!obj.startwith("Ca"));
274
275 assert(!obj.startwith("C"));
276
277 std::cout << "All the tests passed for startwith method" << std::endl;
278
279 // test for predict_words/recommendation of words based on a given prefix
280
281 std::vector<std::string> pred_words = obj.predict_words("a");
282
283 for (const std::string& str : obj.predict_words("a")) {
284 std::cout << str << std::endl;
285 }
286 assert(pred_words.size() == 8);
287 std::cout << "Returned all words that start with prefix a " << std::endl;
288 pred_words = obj.predict_words("app");
289
290 for (const std::string& str : pred_words) {
291 std::cout << str << std::endl;
292 }
293
294 assert(pred_words.size() == 5);
295 std::cout << "Returned all words that start with prefix app " << std::endl;
296 pred_words = obj.predict_words("A");
297
298 for (const std::string& str : pred_words) {
299 std::cout << str << std::endl;
300 }
301
302 assert(pred_words.size() == 1);
303 std::cout << "Returned all words that start with prefix A " << std::endl;
304 pred_words = obj.predict_words("bu");
305
306 for (const std::string& str : pred_words) {
307 std::cout << str << std::endl;
308 }
309
310 assert(pred_words.size() == 2);
311 std::cout << "Returned all words that start with prefix bu " << std::endl;
312
313 // tests for delete method
314
315 obj.delete_word("app");
316 assert(!obj.search("app"));
317 std::cout << "word app is deleted sucessful" << std::endl;
318
319 pred_words = obj.predict_words("app");
320 for (const std::string& str : pred_words) {
321 std::cout << str << std::endl;
322 }
323 assert(pred_words.size() == 4);
324 std::cout << "app is deleted sucessful" << std::endl;
325
326 // test case for Chinese language
327
328 obj.insert("苹果");
329 assert(obj.startwith("苹"));
330 pred_words = obj.predict_words("h");
331
332 assert(pred_words.size() == 0);
333 std::cout << "No word starts with prefix h in trie" << std::endl;
334
335 std::cout << "All tests passed" << std::endl;
336}
337
342int main() {
343 test(); // run self-test implementaions
344 return 0;
345}
Trie class, implementation of trie using hashmap in each trie node for all the characters of char16_t...
std::vector< std::string > get_all_words(std::vector< std::string > results, const std::shared_ptr< Node > &element, std::string prefix)
helper function to predict/recommend words that starts with a given prefix from the end of prefix's n...
std::shared_ptr< Node > root_node
declaring root node of trie
void insert(const std::string &word)
insert the string into the trie
void delete_word(std::string word)
delete a word/string from a trie
bool search(const std::string &word)
search a word/string inside the trie
std::vector< std::string > predict_words(const std::string &prefix)
predict/recommend a word that starts with a given prefix
bool startwith(const std::string &prefix)
search a word/string that starts with a given prefix
for IO operations
Functions for Trie data structure using hashmap implementation.
std::unordered_map< char16_t, std::shared_ptr< Node > > children
bool word_end
boolean variable to represent the node end
static void test()
Self-test implementations.
int main()
Main function.