Skip to content

Commit ae069b8

Browse files
committed
"Implement Trie (Prefix Tree)"
1 parent d4246e7 commit ae069b8

File tree

2 files changed

+264
-1
lines changed

2 files changed

+264
-1
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Compile **C++** files using command:
3737
| 211 | [Add and Search Word - Data structure design] | |
3838
| 210 | [Course Schedule II] | |
3939
| 209 | [Minimum Size Subarray Sum] | |
40-
| 208 | [Implement Trie (Prefix Tree)] | |
40+
| 208 | [Implement Trie (Prefix Tree)] | [C](src/208.c) |
4141
| 207 | [Course Schedule] | |
4242
| 206 | [Reverse Linked List] | [C](src/206.c) |
4343
| 205 | [Isomorphic Strings] | [C](src/205.c) |

Diff for: src/208.c

+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <stdbool.h>
4+
#include <assert.h>
5+
6+
/* I implement Trie using left-child right-sibling binary tree. */
7+
/* https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree */
8+
/* It's not an easy way, the code may not be so elegant. */
9+
/* We can use an array each node to store the children pointers in easy way. */
10+
11+
struct TrieNode {
12+
char val;
13+
struct TrieNode *child; /* most left child */
14+
struct TrieNode *sibling; /* brothers of the current child*/
15+
};
16+
17+
/** Initialize your data structure here. */
18+
struct TrieNode* trieCreate() {
19+
struct TrieNode *dummy = (struct TrieNode *)malloc(sizeof(struct TrieNode));
20+
dummy->val = '\0';
21+
dummy->child = NULL;
22+
dummy->sibling = NULL;
23+
24+
return dummy;
25+
}
26+
27+
/**
28+
* Iterative Method
29+
*/
30+
31+
/** Inserts a word into the trie. */
32+
void insert(struct TrieNode* root, char* word) {
33+
if (root == NULL || word == NULL) return;
34+
35+
struct TrieNode **p = &(root->child);
36+
struct TrieNode *new_node = NULL;
37+
38+
while (*word != '\0') {
39+
/* get common prefix */
40+
while (*p) {
41+
if ((*p)->val == *word) {
42+
p = &((*p)->child);
43+
word++;
44+
}
45+
else {
46+
p = &((*p)->sibling);
47+
}
48+
}
49+
50+
new_node = (struct TrieNode *)malloc(sizeof(struct TrieNode));
51+
new_node->val = *word;
52+
new_node->child = NULL;
53+
new_node->sibling = NULL;
54+
55+
*p = new_node;
56+
p = &((*p)->child); /* move forward */
57+
word++;
58+
}
59+
60+
/* put the EOL character in the tree */
61+
new_node = (struct TrieNode *)malloc(sizeof(struct TrieNode));
62+
new_node->val = '\0';
63+
new_node->child = NULL;
64+
new_node->sibling = NULL;
65+
66+
if (*p) {
67+
p = &((*p)->child);
68+
*p = new_node;
69+
}
70+
else {
71+
*p = new_node;
72+
}
73+
}
74+
75+
/** Returns if the word is in the trie. */
76+
bool search(struct TrieNode* root, char* word) {
77+
if (root == NULL || word == NULL) return false;
78+
79+
if (root->child == NULL) return false;
80+
81+
struct TrieNode *p = root->child;
82+
83+
while (p && *word != '\0') {
84+
if (p->val == *word) {
85+
p = p->child;
86+
word++;
87+
}
88+
else {
89+
p = p->sibling;
90+
}
91+
}
92+
93+
/* check if we have an EOL in the siblings */
94+
while (p) {
95+
if (p->val == '\0') return true;
96+
p = p->sibling;
97+
}
98+
99+
return false;
100+
}
101+
102+
/** Returns if there is any word in the trie
103+
that starts with the given prefix. */
104+
bool startsWith(struct TrieNode* root, char* prefix) {
105+
if (root == NULL || prefix == NULL) return false;
106+
107+
if (root->child == NULL) return false;
108+
109+
struct TrieNode *p = root->child;
110+
111+
while (p && *prefix != '\0') {
112+
if (p->val == *prefix) {
113+
p = p->child;
114+
prefix++;
115+
}
116+
else {
117+
p = p->sibling;
118+
}
119+
}
120+
121+
if (p && *prefix == '\0') return true;
122+
else return false;
123+
}
124+
125+
/** Deallocates memory previously allocated for the TrieNode. */
126+
void trieFree(struct TrieNode* root) {
127+
if (root == NULL) return;
128+
129+
/* Post order traversal ( */
130+
trieFree(root->child);
131+
trieFree(root->sibling);
132+
free(root);
133+
}
134+
135+
/**
136+
* Recursive Method (insert, search and startWith)
137+
*/
138+
139+
void insert_r(struct TrieNode* root, char* word) {
140+
if (root == NULL || word == NULL) return;
141+
142+
if (root->child != NULL) {
143+
if (root->child->val == *word) {
144+
if (*word == '\0') return;
145+
insert_r(root->child, word + 1);
146+
}
147+
else {
148+
/* get most right sibling */
149+
struct TrieNode **p = &(root->child->sibling);
150+
while (*p) {
151+
if ((*p)->val == *word) {
152+
if (*word == '\0') return;
153+
insert_r(*p, word + 1);
154+
return;
155+
}
156+
p = &((*p)->sibling);
157+
}
158+
159+
struct TrieNode *new_node
160+
= (struct TrieNode *)malloc(sizeof(struct TrieNode));
161+
new_node->val = *word;
162+
new_node->child = NULL;
163+
new_node->sibling = NULL;
164+
165+
*p = new_node;
166+
167+
if (*word == '\0') return;
168+
insert_r(*p, word + 1);
169+
}
170+
}
171+
else {
172+
/* if the child is NULL, the sibling must be NULL too */
173+
/* so we don't need to check that. */
174+
struct TrieNode *new_node
175+
= (struct TrieNode *)malloc(sizeof(struct TrieNode));
176+
new_node->val = *word;
177+
new_node->child = NULL;
178+
new_node->sibling = NULL;
179+
180+
root->child = new_node;
181+
if (*word == '\0') return;
182+
insert_r(root->child, word + 1);
183+
}
184+
}
185+
186+
bool search_r(struct TrieNode* root, char* word) {
187+
if (root == NULL || word == NULL) return false;
188+
189+
if (root->child == NULL) return false;
190+
191+
if (root->child->val == *word) {
192+
if (*word == '\0') return true;
193+
else return search_r(root->child, word + 1);
194+
}
195+
else {
196+
struct TrieNode *p = root->child->sibling;
197+
while (p) {
198+
if (p->val == *word) {
199+
if (*word == '\0') return true;
200+
else return search_r(p, word + 1);
201+
}
202+
p = p->sibling;
203+
}
204+
return false;
205+
}
206+
}
207+
208+
bool startsWith_r(struct TrieNode* root, char* prefix) {
209+
if (root == NULL || prefix == NULL) return false;
210+
211+
if (root->child == NULL) return false;
212+
213+
if (*prefix == '\0') return true;
214+
215+
if (root->child->val == *prefix) {
216+
return startsWith_r(root->child, prefix + 1);
217+
}
218+
else {
219+
struct TrieNode *p = root->child->sibling;
220+
while (p) {
221+
if (p->val == *prefix) {
222+
return startsWith_r(p, prefix + 1);
223+
}
224+
p = p->sibling;
225+
}
226+
return false;
227+
}
228+
}
229+
230+
int main() {
231+
232+
struct TrieNode* node = trieCreate();
233+
234+
assert(search(node, "some") == false);
235+
insert(node, "s");
236+
assert(search(node, "some") == false);
237+
assert(search(node, "s0") == false);
238+
239+
insert(node, "some");
240+
assert(search(node, "some") == true);
241+
242+
insert(node, "somestring");
243+
insert(node, "someword");
244+
insert(node, "word");
245+
246+
assert(search(node, "word") == true);
247+
assert(search(node, "somestring") == true);
248+
assert(search(node, "someword") == true);
249+
assert(search(node, "somew") == false);
250+
assert(search(node, "somes") == false);
251+
assert(search(node, "somex") == false);
252+
253+
assert(startsWith(node, "some") == true);
254+
assert(startsWith(node, "somew") == true);
255+
assert(startsWith(node, "somes") == true);
256+
assert(startsWith(node, "somex") == false);
257+
258+
trieFree(node);
259+
260+
printf("all tests passed!\n");
261+
262+
return 0;
263+
}

0 commit comments

Comments
 (0)