-
Notifications
You must be signed in to change notification settings - Fork 0
/
trie.c
198 lines (175 loc) · 3.72 KB
/
trie.c
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
/*
* George 'papanikge' Papanikolaou CEID Data Structures 2013
* Simple Trie Implementation
* See other files about licensing
*/
/*
* Tries are represented by the TrieNode which have a value and a (latin
* alphabet size) array of pointers to children (not compressed).
* Functions work by traversing the string one by one character
*/
#include "core.h"
#include "trie.h"
#include <ctype.h>
/*
* convert a whole string to lowercase
* also keeping only alpharithmetic characters
* !!! the memory it returns needs to be free()d
*/
static char* setup_string(char *str)
{
int i,j;
char *p, *start;
start = p = (char*) smalloc(strlen(str) + 1);
for (i = j = 0; str[i] != '\0'; i++)
if (isalpha(str[i])) {
p[j] = str[i];
j++;
}
p = start;
while (*p) {
*p = tolower(*p);
p++;
}
return start;
}
/* Add a key to the trie and create nodes as needed (recursively) */
static TrieNode* _trie_insert(char *s, Book *v, TrieNode *t)
{
int index;
if (*s == '\0') {
/* reached the end */
t->key = '\0';
t->value = v;
} else {
/* get index in 0..25 */
index = *s - 'a';
/* check for existence */
if(!t->edges[index])
t->edges[index] = trie_initialize(*s);
/* key, for later */
t->key = *s;
/* one more shift for the next character */
s++;
t->edges[index] = _trie_insert(s, v, t->edges[index]);
}
return t;
}
/* traverse the string and delete if there is nothing else (recursively) */
static TrieNode* _trie_delete(char *s, TrieNode *t)
{
int i;
int index;
/* true by default */
int all_null = 1;
/* optimization flag in case of non-existence */
static int no_need = 0;
/* safety */
if (!t || no_need)
return NULL;
if (*s == '\0') {
/* reached it */
free(t);
return NULL;
} else {
/* get index in 0..25 */
index = *s - 'a';
/* if not found, we just return */
if(!t->edges[index]) {
no_need = 1;
return NULL;
}
/* shift the head of the string to continue recursing */
s++;
t->edges[index] = _trie_delete(s, t->edges[index]);
/* we need to delete all the nodes that lead to the one we removed
* if there are no other children */
for (i = 0; i < 26; i++)
if (t->edges[i] != NULL)
all_null = 0;
if (all_null) {
free(t);
return NULL;
}
else
return t;
}
}
/* traverse the trie and return the value if found (recursively) */
static Book* _trie_find(char *s, TrieNode *t)
{
Book *b;
int index;
/* safety */
if (!t)
return NULL;
if (*s == '\0')
/* found it */
return t->value;
else {
/* get index in 0..25 */
index = *s - 'a';
/* if not found, we need to return NULL up the stack */
if(!t->edges[index])
return NULL;
/* shift the head of the string to continue recursing */
s++;
b = _trie_find(s, t->edges[index]);
/* return whatever came back, Book or NULL */
return b;
}
}
/* helper for when closing up (recursively) */
void trie_dispose(TrieNode* t)
{
int i;
if (t) {
for (i = 0; i < 26; i++)
trie_dispose(t->edges[i]);
free(t);
}
return;
}
/* memory allocation and assignments to new node */
TrieNode* trie_initialize(char key)
{
int i;
TrieNode *node;
node = (TrieNode*) smalloc(sizeof(TrieNode));
node->key = key;
node->value = NULL;
/* null-ing all nodes */
for (i = 0; i < 26; i++)
node->edges[i] = NULL;
return node;
}
/*
* wrapper functions to set things (like strings) up
*/
TrieNode* trie_insert(char *str, Book *v, TrieNode *t)
{
char *s;
TrieNode *T;
s = setup_string(str);
T = _trie_insert(s, v, t);
free(s);
return T;
}
TrieNode* trie_delete(char *str, TrieNode *t)
{
char *s;
TrieNode *T;
s = setup_string(str);
T = _trie_delete(s, t);
free(s);
return T;
}
Book* trie_find(char *str, TrieNode *t)
{
char *s;
Book *T;
s = setup_string(str);
T = _trie_find(s, t);
free(s);
return T;
}