-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDictionaryTrie.cpp
More file actions
311 lines (280 loc) · 8.51 KB
/
Copy pathDictionaryTrie.cpp
File metadata and controls
311 lines (280 loc) · 8.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/**
* Name: Rui Deng
* Dadong Jing
* Data: Feb 18, 2016
* Overview: this file is to implement the functionality of DictionaryTrie
* Assignment number: PA3
*/
#include "util.hpp"
#include "DictionaryTrie.hpp"
#include <string>
#include <iostream>
#include <utility>
#include <queue>
#include <vector>
/* Create a new Dictionary that uses a Trie back end */
DictionaryTrie::DictionaryTrie()
{
//initialize a root
root = new TrieNode();
}
/**
* Insert a word with its frequency into the dictionary.
* Return true if the word was inserted, and false if it
* was not (i.e. it was already in the dictionary or it was
* invalid (empty string)
*/
bool DictionaryTrie::insert(std::string word, unsigned int freq)
{
//if empty string, invalid so return false
if(word.length() == 0)
{
return false;
}
//if the word is already in dictionary, return false
if(this->find(word) == true)
{
return false;
}
//get the root and initialize an iterator to go through each character
TrieNode *curr = root;
std::string::iterator track = word.begin();
//while loop to go through the word passed in
while(track != word.end())
{
//get the single character and get the index of it to insert
char singleW = *track;
int index = (int)singleW - (int)'a';
//if the char is a space, make it to be the last child
if(index < 0)
{
index = 26;
}
//create a new node if there's no node existed in the child place
if(curr->child[index] == 0)
{
TrieNode *newNode = new TrieNode();
//link the parent with its child and link child with parent
newNode->parent = curr;
curr->child[index] = newNode;
}
//go down the trie and to the next character
curr = curr->child[index];
track++;
}
//store the frequency to the node
curr->freq = freq;
//update the maxCount for the trie
std::string::iterator track1 = word.begin();
while(track1 != word.end())
{
curr = curr->parent;
if(freq > curr->maxCount)
{
curr->maxCount = freq;
}
track1++;
}
//return true after insertion
return true;
}
/* Return true if word is in the dictionary, and false otherwise */
bool DictionaryTrie::find(std::string word) const
{
//if the word is empty, return false
if(word.length() == 0)
{
return false;
}
//get the root and initialize an iterator to go through each character
TrieNode *curr = root;
std::string::iterator track = word.begin();
//while loop to go through the word passed in
while(track != word.end())
{
//get the single character and get the index of it to find
char singleW = *track;
int index = (int)singleW - (int)'a';
//if the char is a space, it shoudld be the last child
if(index < 0)
{
index = 26;
}
//if cannot find the child in that specific index, return false
if(curr->child[index] == 0)
{
return false;
}
//go down the trie and to the next character
curr = curr->child[index];
track++;
}
//if the frequency of the word is not 0, return true
if(curr->freq != 0)
{
return true;
}
//otherwise return false
return false;
}
/* Return up to num_completions of the most frequent completions
* of the prefix, such that the completions are words in the dictionary.
* These completions should be listed from most frequent to least.
* If there are fewer than num_completions legal completions, this
* function returns a vector with as many completions as possible.
* If no completions exist, then the function returns a vector of size 0.
* The prefix itself might be included in the returned words if the prefix
* is a word (and is among the num_completions most frequent completions
* of the prefix)
*/
std::vector<std::string> DictionaryTrie::predictCompletions(std::string prefix,
unsigned int num_completions)
{
std::vector<std::string> words;
//create a priority queue in which smaller freq pair in at front
std::priority_queue<std::pair<std::string,unsigned int>,
std::vector<std::pair<std::string,unsigned int> >,
pairCmp> pq;
//create a empty pair
std::pair<std::string,unsigned int> empty(prefix,0);
//push the empty pair into the pq for num_completions times,
//so that there is something in the pq for comparison in searchHelper
//method
for(unsigned int j = 0; j < num_completions; j++)
{
pq.push(empty);
}
//if the prefix is empty or num_completions is negative or zero,
//return
if(prefix.length() == 0 || num_completions <= 0)
{
return words;
}
//create a TrieNode object
TrieNode *curr = root;
std::string::iterator track = prefix.begin();
//loop through the end of the prefix string
while(track != prefix.end())
{
char singleW = *track;
int index = (int)singleW - (int)'a';
if(index < 0)
{
index = 26;
}
if(curr->child[index] == 0)
{
return words;
}
curr = curr->child[index];
track++;
}
//call searchHelper method
searchHelper(curr,pq,prefix);
//pop the pq for num_completions times
for(unsigned int i = 0; i < num_completions; i++)
{
//only push to the vector if it has positive frequency
if(!pq.empty())
{
if(pq.top().second != 0)
{
words.push_back(pq.top().first);
pq.pop();
}
else
{
pq.pop();
}
}
}
//call reverse method to get the right ordering(max--min)
words = reverse(words);
return words;
}
/* searchHelper method that insert the correct element into the pq */
void DictionaryTrie::searchHelper(TrieNode *curr,
std::priority_queue<std::pair<std::string,unsigned int>,
std::vector<std::pair<std::string,unsigned int> >,
pairCmp>& pq, std::string prefix)
{
//if the curr TrieNode's frequency is greater than zero
if(curr->freq > 0)
{
//compare with the first element's freq in the pq
if(curr->freq > pq.top().second)
{
//pop the first pair
pq.pop();
//create a new pair and push back to the pq
std::pair<std::string,unsigned int> newPair(prefix, curr->freq);
pq.push(newPair);
}
}
//check if the maxCount of the TrieNode is greater than the top
//pair frequency
if(curr->maxCount > pq.top().second)
{
//loop through all the child
for(int i = 0; i < 27; i++)
{
//if the child is not null
if(curr->child[i] != 0)
{
//update the prefix
std::string newPrefix(prefix);
if(i == 26)
{
newPrefix += " ";
}
else
{
char toAdd = (char)('a' + i);
std::string addString(1, toAdd);
newPrefix.append(addString);
}
//recursivly call the searchHelper method
searchHelper(curr->child[i],pq,newPrefix);
}
}
}
return;
}
/* reverse method to get the right ording in the vector */
std::vector<std::string>DictionaryTrie::reverse(std::vector<std::string> in)
{
//create a new vector for return purpose
std::vector<std::string> returnV;
//loop from the back of the input vector
for(int i = (int)in.size() - 1; i >= 0; i--)
{
//get the string and push back to the return vector
std::string T = in[i];
returnV.push_back(T);
}
return returnV;
}
/* Destructor */
DictionaryTrie::~DictionaryTrie()
{
//calling the helper method using postorder to delete all the nodes
deleteAll(root);
}
/**
* a helper method using postorder to delete nodes
*/
void DictionaryTrie::deleteAll(TrieNode *n)
{
//if the node passed in is null, return
if(n == 0)
{
return;
}
//for each child in the node's children array, recursively call
for(int i = 0; i < 27; i++)
{
deleteAll(n->child[i]);
}
//delete the node itself
delete n;
}