-
Notifications
You must be signed in to change notification settings - Fork 215
/
Copy pathtrie.cpp
252 lines (225 loc) · 7.23 KB
/
trie.cpp
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
/*
https://leetcode.com/problems/implement-trie-prefix-tree/
Implement Trie (also called 'prefix tree') which supports lowercase letters only,
a search tree with multiple childrens (26 in this case).
methods: Insert - push new string into the tree.
Delete - remove string from the tree.
search - check if a string is already pushed into the tree.
StartWith - check if sum prefix is appear in the tree.
Example:
int main(){
Trie trie;
trie.Insert("abcd");
trie.Search("abcd") // return true;
trie.Search("ab") // return false;
trie.startWith("ab") // return true;
trie.Insert("ab");
trie.Search("ab") // return true;
trie.Delete("ab")
trie.Search("ab") // return false;
trie.Search("abcd") // return true;
return 0;
}
Time Complexity:
Insert() / Search() / startWith() | Average & Worst-case == O(m) | m == number of chars in string.
Space Complexity:
Space complexity for a trie: O(k * N) | k == size of the node, N == number of the different nodes.
*/
#include <string>
#include <vector>
enum{CHARS_IN_ALPHABET = 26};
class TrieNode{
public:
TrieNode() : vec(CHARS_IN_ALPHABET, nullptr), end_of_str(false) {};
// every node has a vector for his childrens and a flag to mark - end of word.
std::vector<TrieNode*> vec;
bool end_of_str;
};
/****************************************************************************/
class Trie {
public:
Trie();
~Trie();
// non-copyable class
Trie(const Trie& other) = delete;
Trie& operator= (const Trie& other) = delete;
void Insert(std::string word);
bool Delete(std::string word);
bool Search(std::string word);
bool startWith(std::string prefix);
void Destroy(TrieNode* root);
private:
enum RecDeleteStatus{NOT_FOUND = -1, DELETE = 0 , COMPLITE = 1};
RecDeleteStatus RecDelete(TrieNode* curr_node, const char* string_ptr);
bool IsLeaf(TrieNode* node);
TrieNode* CreatNodes(TrieNode* node_runner, const char* rest_letters);
TrieNode* FindLastChar(const char* first_char_string);
TrieNode* m_root;
};
/****************************************************************************/
Trie::Trie() // Ctor
{
m_root = new TrieNode();
}
/****************************************************************************/
Trie::~Trie() // Dtor
{
Destroy(m_root);
delete m_root;
}
/****************************************************************************/
// function for push a word(string) inside the trie
void Trie::Insert(std::string word)
{
const char* string_ptr = word.data();
TrieNode* node_runner = m_root;
while(*string_ptr)
{
// if this node does not have this latter as a child yet.
if(!node_runner->vec[*string_ptr - 'a'])
{
node_runner = CreatNodes(node_runner, string_ptr);
break;
}
node_runner = node_runner->vec[*string_ptr - 'a'];
++string_ptr;
}
// mark node as end of word.
node_runner->end_of_str = true;
}
/****************************************************************************/
// function for remove a word from the trie, if the word or part of her suffix
// stand alone, the whole node will be removed.
bool Trie::Delete(std::string word)
{
if(RecDelete(m_root, word.data()) != NOT_FOUND)
{
return true;
}
return false;
}
/****************************************************************************/
// function for check if a string is already pushed into the tree.
bool Trie::Search(std::string word)
{
TrieNode* node = FindLastChar(word.data());
// if FindLastChar return nullptr the word isnt in the trie,
// if the word is found but it just a prefix of another word, return false
if(node == nullptr || node->end_of_str == false){
return false;
}
return true;
}
/****************************************************************************/
// function for check if sum prefix is appear in the tree.
bool Trie::startWith(std::string prefix)
{
TrieNode* node = FindLastChar(prefix.data());
// if FindLastChar return nullptr the word isnt in the trie,
if(node == nullptr){
return false;
}
return true;
}
/****************************************************************************/
// Recursive function for delete a word and the whole node if the word or part
// of her suffix stand alone. if the word is prefix of another word, no nodes
// will be removed
Trie::RecDeleteStatus Trie::RecDelete(TrieNode* curr_node, const char* string_ptr)
{
if(curr_node == nullptr)
{
return NOT_FOUND;
}
if(*string_ptr == '\0')
{
return DELETE;
}
int char_idx = *string_ptr - 'a';
RecDeleteStatus status = RecDelete(curr_node->vec[char_idx], string_ptr + 1);
if(status == DELETE)
{
if(IsLeaf(curr_node->vec[char_idx]))
{
delete curr_node->vec[char_idx];
curr_node->vec[char_idx] = nullptr;
return DELETE;
}
else if(*(string_ptr + 1) == '\0')
{
if(curr_node->vec[char_idx]->end_of_str)
{
curr_node->vec[char_idx]->end_of_str = false;
return DELETE;
}
else
{
return NOT_FOUND;
}
}
}
if(status == NOT_FOUND)
{
return NOT_FOUND;
}
return COMPLITE;
}
/****************************************************************************/
// function to check if node does not have childrens
bool Trie::IsLeaf(TrieNode* curr_node)
{
for(auto it : curr_node->vec)
{
if(it != nullptr)
{
return false;
}
}
return true;
}
/****************************************************************************/
// function for create and push new nodes ,from the input node(node_runner)
// according to the string(string_ptr) that must have a null termination sign.
TrieNode* Trie::CreatNodes(TrieNode* node_runner, const char* string_ptr)
{
while(*string_ptr)
{
TrieNode* new_node = new TrieNode();
node_runner->vec[*string_ptr - 'a'] = new_node;
node_runner = new_node;
++string_ptr;
}
return node_runner;
}
/****************************************************************************/
// function for search and return the node of the last character in a string
// return nullptr if the word is not found.
TrieNode* Trie::FindLastChar(const char* string_ptr)
{
TrieNode* node_runner = m_root;
while(*string_ptr)
{
TrieNode* next_node = node_runner->vec[*string_ptr - 'a'];
if(nullptr == next_node)
{
return nullptr;
}
node_runner = next_node;
++string_ptr;
}
return node_runner;
}
/****************************************************************************/
// destroy all nodes inside the trie except the root
void Trie::Destroy(TrieNode* node)
{
if(node == nullptr)
{
return;
}
for(auto it : node->vec)
{
Destroy(it);
delete it;
}
}