TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
trie_multiple_search.cpp
Go to the documentation of this file.
1
13#include <algorithm>
14#include <cassert>
15#include <cctype>
16#include <cstdint>
17#include <cstring>
18#include <iostream>
19#include <queue>
20
32namespace trie_operations {
37class Tnode {
38 private:
39 static constexpr uint8_t ENGLISH_ALPHABET_SIZE = 26;
40 // pointers to alphabets
41 std::vector<Tnode *> english;
42
43 // To mark the end of word
44 bool endOfWord;
45
46 // To store the frequency of searches for the word
47 uint32_t frequency;
48
49 public:
50 Tnode() {
51 english.resize(ENGLISH_ALPHABET_SIZE, nullptr);
52 endOfWord = false;
53 frequency = 0;
54 }
55 // Copy Constructor
56 Tnode(const Tnode &node) {
57 english = node.english;
58 endOfWord = node.endOfWord;
59 frequency = node.frequency;
60 }
61
62 Tnode &operator=(const Tnode &node) = default;
63
64 Tnode(Tnode &&) = default;
65
66 Tnode &operator=(Tnode &&) = default;
72 inline uint8_t numberOfChildren(Tnode *node) {
73 return ENGLISH_ALPHABET_SIZE -
74 std::count(node->english.begin(), node->english.end(), nullptr);
75 }
76
77 // Functions to perform operations on trie
78 void Insert(const std::string &entry);
79 void Delete(std::string entry);
80 void DeleteFrom(Tnode *delete_from, std::string delete_string,
81 int remove_index);
82 bool SearchPresence(const std::string &key);
83 void SuggestAutocomplete(Tnode *new_root, const std::string &prefix);
84 void SearchSuggestions(const std::string &key);
86 Tnode *new_root, const std::string &prefix,
87 std::priority_queue<std::pair<int, std::string> > *suggestions);
88 void SearchFreqSuggestions(const std::string &key);
89 void SelectionTop_3(
90 std::priority_queue<std::pair<int, std::string> > *suggestions);
91
92 // To free up the dynamically allocated objects
93 ~Tnode() {
94 int i = 0;
95 for (i = 0; i < ENGLISH_ALPHABET_SIZE; i++) {
96 if (english[i]) {
97 delete english[i];
98 }
99 }
100 }
101};
102
107void Tnode::Insert(const std::string &entry) {
108 Tnode *cur_pos = this;
109 int letter_index = 0;
110
111 for (auto &i : entry) {
112 // To ignore case
113 letter_index = tolower(i) - 97;
114
115 // Allocate a node for each character of entry if not present in the
116 // trie
117 if (cur_pos->english[letter_index] == nullptr) {
118 cur_pos->english[letter_index] = new Tnode();
119 }
120
121 cur_pos = cur_pos->english[letter_index];
122 }
123 // cur_pos points to the last char, mark it as end of word
124 cur_pos->endOfWord = true;
125}
126
137void Tnode::DeleteFrom(Tnode *delete_from, std::string delete_string,
138 int remove_index) {
139 if (delete_string.size() == remove_index) {
140 int letter_index = tolower(delete_string[remove_index]) - 97;
141
142 DeleteFrom(delete_from->english[letter_index], delete_string,
143 remove_index + 1);
144
145 delete delete_from;
146 }
147}
148
153void Tnode::Delete(std::string entry) {
154 Tnode *cur_pos = this,
155 *delete_from = this; // Current pointer pointing to root
156 int letter_index = 0, delete_from_index = 0, i = 0, n = entry.size();
157
158 for (i = 0; i < n; i++) {
159 // To ignore case
160 letter_index = tolower(entry[i]) - 97;
161
162 // Display error message when given entry is not present in the tree
163 if (cur_pos->english[letter_index] == nullptr) {
164 std::cout << "Entry not Found" << std::endl;
165 return;
166 }
167 // If the current node is end of word for the current prefix or if it
168 // has 2 or more branches It cannot be deleted while deleting the
169 // required entry.
170 if (numberOfChildren(cur_pos) > 1 || cur_pos->endOfWord) {
171 delete_from = cur_pos; // denotes the beginning of the shortest
172 // suffix that is allowed to be deleted
173 delete_from_index = i - 1; // Beginning index of the suffix
174 // corresponding to the 'entry'
175 }
176
177 // Traversing through the entry
178 cur_pos = cur_pos->english[letter_index];
179 }
180
181 // cur_pos now points to the last char of entry. Display message if that
182 // entry does not exist
183 if (!cur_pos->endOfWord) {
184 std::cout << "Entry not Found" << std::endl;
185 return;
186 }
187
188 // If cur_pos is not a leaf node, unmark end of word and assign 0 to it's
189 // frequency for deletion
190 if (numberOfChildren(cur_pos)) {
191 cur_pos->endOfWord = false;
192 cur_pos->frequency = 0;
193 return;
194 }
195
196 // The first character of the suffix to be deleted
197 letter_index = tolower(entry[delete_from_index + 1]) - 97;
198 // Point cur_pos to the next node
199 cur_pos = delete_from->english[letter_index];
200 // Sever the connection from the main trie
201 delete_from->english[letter_index] = nullptr;
202
203 // If number of characters in the suffix are more than 1, recursively delete
204 // each character starting from cur_pos using the helper function
205 if (n > delete_from_index + 2) {
206 DeleteFrom(cur_pos, entry, delete_from_index + 2);
207 }
208 // If the suffix is only 1 char in length
209 else {
210 delete cur_pos;
211 }
212}
213
220bool Tnode::SearchPresence(const std::string &key) {
221 Tnode *cur_pos = this;
222 int letter_index = 0;
223
224 for (auto &i : key) {
225 letter_index = tolower(i) - 97;
226 // If any character in the order of the key is absent, word not found!
227 if (cur_pos->english[letter_index] == nullptr) {
228 return false;
229 }
230 cur_pos = cur_pos->english[letter_index];
231 }
232 // Word is only present in the trie if the key is a valid complete entry and
233 // not just a prefix.
234 if (cur_pos->endOfWord) {
235 (cur_pos->frequency)++;
236 return true;
237 } else {
238 return false;
239 }
240}
241
249void Tnode::SuggestAutocomplete(Tnode *new_root, const std::string &prefix) {
250 // Iterate through all 26 nodes as we have to print all strings with the
251 // given prefix
252 int i = 0;
253 for (i = 0; i < ENGLISH_ALPHABET_SIZE; i++) {
254 if (new_root->english[i] != nullptr) {
255 // Print the sugestion only if it's a valid complete entry and not
256 // just a prefix
257 if (new_root->english[i]->endOfWord) {
258 std::cout << prefix + char(i + 97) << std::endl;
259 }
260
261 SuggestAutocomplete(new_root->english[i], prefix + char(i + 97));
262 }
263 }
264}
265
274void Tnode::SearchSuggestions(const std::string &key) {
275 Tnode *cur_pos = nullptr, *prev_pos = nullptr;
276 cur_pos = prev_pos = this; // maintaining 2 pointers, initialized to root
277 int letter_index = 0;
278 std::string prefix =
279 ""; // variable storing the updated value of longest common prefix
280
281 for (auto &i : key) {
282 letter_index = tolower(i) - 97;
283 prev_pos = cur_pos; // Previous pointer updated to point to the last
284 // char of the longest common prefix
285
286 // When the node for the character does not exist, longest prefix has
287 // been determined and SuggestAutocomplete is called
288 if (cur_pos->english[letter_index] == nullptr) {
289 SuggestAutocomplete(prev_pos, prefix);
290 std::cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - "
291 << std::endl;
292 return;
293 }
294 // Updating the longest common prefix
295 prefix += char(tolower(i));
296 cur_pos = cur_pos->english[letter_index];
297 }
298 // If the key is a valid entry of trie, display it @ top of the suggestions
299 if (cur_pos->endOfWord) {
300 std::cout << key << std::endl;
301 (cur_pos->frequency)++;
302 }
303
304 (void)prev_pos; // Idiom to ignore previous pointer
305
306 // Call for suggestions when the search key is present as an entry/a prefix
307 // in the trie
308 SuggestAutocomplete(cur_pos, prefix);
309 std::cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - "
310 << std::endl;
311 return;
312}
313
321 std::priority_queue<std::pair<int, std::string> > *suggestions) {
322 // Display Either top 3 or total number of suggestions, whichever is smaller
323 int n = suggestions->size(), Top = 0;
324 Top = n < 3 ? n : 3;
325 while (Top--) {
326 std::cout << suggestions->top().second << std::endl;
327 suggestions->pop();
328 }
329}
330
341 Tnode *new_root, const std::string &prefix,
342 std::priority_queue<std::pair<int, std::string> > *suggestions) {
343 int i = 0;
344 for (i = 0; i < ENGLISH_ALPHABET_SIZE; i++) {
345 if (new_root->english[i] != nullptr) {
346 // Add to sugestions only if it's a valid complete entry and not
347 // just a prefix
348 if (new_root->english[i]->endOfWord) {
349 suggestions->push(std::make_pair(
350 new_root->english[i]->frequency, prefix + char(i + 97)));
351 }
352
353 SuggestFreqAutocomplete(new_root->english[i], prefix + char(i + 97),
354 suggestions);
355 }
356 }
357}
358
368void Tnode::SearchFreqSuggestions(const std::string &key) {
369 Tnode *cur_pos = nullptr, *prev_pos = nullptr;
370 cur_pos = prev_pos = this; // maintaining 2 pointers, initialized to root
371 int letter_index = 0;
372 std::string prefix =
373 ""; // variable storing the updated value of longest common prefix
374 std::priority_queue<std::pair<int, std::string> >
375 suggestions; // max heap to store (frequency, word) in descending order
376 // of freq
377
378 std::priority_queue<std::pair<int, std::string> > *Suggestions =
379 &suggestions;
380
381 for (auto &i : key) {
382 letter_index = tolower(i) - 97;
383 prev_pos = cur_pos; // Previous pointer updated to point to the last
384 // char of the longest common prefix
385
386 // When the node for the character does not exist, longest prefix has
387 // been determined and SuggestFreqAutocomplete is called
388 if (cur_pos->english[letter_index] == nullptr) {
389 SuggestFreqAutocomplete(prev_pos, prefix, Suggestions);
390 // To display the top 3 results
391 SelectionTop_3(Suggestions);
392 std::cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - "
393 << std::endl;
394 return;
395 }
396 // Updating the longest common prefix
397 prefix += char(tolower(i));
398 cur_pos = cur_pos->english[letter_index];
399 }
400 // If the key is a valid entry of trie, display it @ top of the suggestions
401 if (cur_pos->endOfWord) {
402 (cur_pos->frequency)++;
403 std::cout << key << std::endl;
404 }
405
406 (void)prev_pos; // Idiom to ignore previous pointer
407
408 // Call for Suggestions when the search key is present as an entry/a prefix
409 // in the trie
410 SuggestFreqAutocomplete(cur_pos, prefix, Suggestions);
411 // Display the top 3 results
412 SelectionTop_3(Suggestions);
413
414 std::cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - "
415 << std::endl;
416 return;
417}
418} // namespace trie_operations
419} // namespace operations_on_datastructures
420
425static void test() {
427 std::vector<std::string> inputs = {
428 "abcde", "sss", "ssss", "ssst", "sssu", "sssv",
429 "sst", "ssts", "sstt", "sstu", "tutu", "tutuv",
430 "tutuu", "tutuvs", "tutus", "tvst", "tvsu", "vvvv"};
431
432 for (auto &i : inputs) {
433 root->Insert(i);
434 }
435 // Search an existing entry
436 assert(root->SearchPresence("vvvv"));
437 std::cout << root->SearchPresence("vvvv") << std::endl;
438 // Delete it
439 root->Delete("vvvv");
440 // Search for the entry again
441 assert(!root->SearchPresence("vvvv"));
442 std::cout << root->SearchPresence("vvvv") << std::endl;
443
444 std::cout << root->SearchPresence("tutu") << std::endl;
445 root->SearchSuggestions("tutu");
446 std::cout << root->SearchPresence("tutu") << std::endl;
447
448 root->SearchSuggestions("tutuv");
449 std::cout << root->SearchPresence("tutuv") << std::endl;
450
451 root->SearchSuggestions("tutuvs");
452
453 root->SearchFreqSuggestions(
454 "tu"); // The top 3 frequent entries with prefix tu are tutu, tutuv &
455 // tutuvs respectively
456 root->SearchSuggestions(
457 ""); // Empty search to list all the entries in the trie
458}
459
466int main(int argc, char const *argv[]) {
467 test(); // run self-test implementations
468 return 0;
469}
Class defining the structure of trie node and containing the methods to perform operations on them.
void SuggestAutocomplete(Tnode *new_root, const std::string &prefix)
Recursive function to suggest all the entries of trie which have a given common prefix.
void SearchSuggestions(const std::string &key)
Lists out all the words in trie with the longest prefix of the search key that is present in the trie...
bool SearchPresence(const std::string &key)
Function to check a word's presence in the trie (Basic)
void SearchFreqSuggestions(const std::string &key)
Lists out the most frequent words in trie with the longest prefix of the search key that is present i...
void Insert(const std::string &entry)
Function to insert a word in the trie.
void SuggestFreqAutocomplete(Tnode *new_root, const std::string &prefix, std::priority_queue< std::pair< int, std::string > > *suggestions)
Recursive function to suggest most frequently searched entries of trie which have a given common pref...
void SelectionTop_3(std::priority_queue< std::pair< int, std::string > > *suggestions)
Function to display the 3 suggestions with highest frequency of search hits.
void DeleteFrom(Tnode *delete_from, std::string delete_string, int remove_index)
Function recursively deletes the substring character by character iterating through the string to be ...
void Delete(std::string entry)
Function to verify presence and hence delete an entry from the trie.
uint8_t numberOfChildren(Tnode *node)
Function to count the number of children a node in the trie has.
int main()
Main function.
Functions for Trie datastructure implementation.
static void test()
Function to test a simple search before and after deleting an entry. And to test out the multiple var...