-
Notifications
You must be signed in to change notification settings - Fork 0
/
orderedSet.c
329 lines (280 loc) · 12.8 KB
/
orderedSet.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
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "orderedSet.h"
#define LEFT (0)
#define RIGHT (1)
#define TREE_EMPTY (0)
#define TREE_EMPTY_HEIGHT (-1)
/*Veena Advani
CPSC 223 - Hwk 8
Due: April 8 2015
Citation: AVL tree code modified from AVL tree section of Aspnes, Lecture Notes on Data Structures
and Programming Techniques, available at http://www.cs.yale.edu/homes/aspnes/classes/223/notes.html,
downloaded April 3rd 2015. */
/*struct for nodes of AVL tree used to represent the ordered set*/
struct node {
char* key; /*string in each tree node*/
struct node* child[2]; /*pointers to the two children*/
int height; /*height of that node*/
size_t size; /*size of this subtree*/
};
/*struct to represent ordered set, which consists of a pointer to the root of the tree*/
struct orderedSet {
struct node *set; /*pointer to root of set*/
};
/*This function creates an ordered set struct, mallocs the memory for it, and sets the root node to 0
to represent an empty tree. Then returns the pointer to the new ordered set*/
struct orderedSet *orderedSetCreate(void) {
struct orderedSet *s;
s = malloc(sizeof(struct orderedSet));
assert(s); /*makes sure malloc worked*/
s->set = TREE_EMPTY;
return s;
}
/*This function takes in a pointer to an ordered set and returns the size of the set*/
size_t orderedSetSize(const struct orderedSet *s) {
if (s->set) { /*if the set consists of a non-empty tree --> return the size associated with the root node struct*/
return s->set->size;
}
else { /*otherwise, the set has an empty tree --> just return a size of 0*/
return 0;
}
}
/*This function takes a pointer to a node and returns the height associated to that node*/
static int treeHeight(const struct node *root) {
if (root==0) { /*if node a null pointer --> empty tree --> return empty tree height (-1)*/
return TREE_EMPTY_HEIGHT;
}
else { /*otherwise, node exists --> return height in the root struct*/
return root->height;
}
}
/*This function takes in a pointer to a root node and returns the size of the tree*/
static size_t treeSize (const struct node *root) {
if (root == 0){ /*root is a null pointer --> size is 0*/
return 0;
} else { /*otherwise, root exists --> return size stored in the struct*/
return root->size;
}
}
/*This function takes in a pointer to a root node and calculates and returns the size of the tree based on the size of its child subtrees*/
static size_t treeCalcSize (const struct node *root) {
size_t size;
if (root == 0) { /* root --> size is 0*/
return 0;
}
else { /* root exists --> size = 1 (current node) + size of left and right subtrees*/
size = 1 + treeSize(root->child[LEFT]) + treeSize(root->child[RIGHT]);
return size;
}
}
/*This function takes in a pointer to a root node and calculates and returns the height of the node based on the height of its children*/
static int treeCalcHeight (const struct node *root) {
if (root == 0) { /*root doesn't exist --> empty tree height of -1*/
return TREE_EMPTY_HEIGHT;
} else { /*otherwise, figure out which subtree has a larger height and set height of current node to larger subree height + 1*/
if (treeHeight(root->child[LEFT]) > treeHeight(root->child[RIGHT])) {
return (treeHeight(root->child[LEFT]) + 1);
} else {
return (treeHeight(root->child[RIGHT]) + 1);
}
}
}
/*this function takes a pointer to a node and if the node is not empty, updates its height and size values based on the values of it's
children*/
static void treeFix (struct node *root) {
if (root) {
root->height = treeCalcHeight(root);
root->size = treeCalcSize(root);
}
}
/*this function takes in a pointer to a root pointer and a direction, and completes one tree rotation*/
static void treeRotate (struct node **root, int direction) {
/*nodes used in rotation*/
struct node *x;
struct node *y;
struct node *b;
y = *root;
assert (y);
x = y->child[direction];
assert(x);
b = x->child[!direction];
/*adjust the root to x*/
*root = x;
/*set x child in opposite direction to y, to start the rotation (y used to be the root)*/
x->child[!direction] = y;
/*set child[direction] of y to complete the rotation*/
y->child[direction] = b;
/*Now that the rotation has been finished, update the height and size information for the y node first, and then the x node, because y is a child
of x */
treeFix(y);
treeFix(x);
}
/*This function takes in a pointer to a root pointer and rebalances the tree*/
static void treeRebalance(struct node **root) {
int tallerKid; /*int to store taller child index*/
if(*root) {
for(tallerKid = 0; tallerKid < 2; tallerKid++) { /*iterate through both children*/
if(treeHeight((*root)->child[tallerKid]) >= treeHeight((*root)->child[!tallerKid]) + 2) { /*if differences in height are 2 or larger --> rebalance*/
/* check if zig-zag: opposite-direction nephew is the tall one */
/* this also covers case where both nephews are too tall */
if(treeHeight((*root)->child[tallerKid]->child[!tallerKid])
>= treeHeight((*root)->child[tallerKid]) - 1) {
/* zig zag case */
treeRotate(&(*root)->child[tallerKid], !tallerKid);
}
/* fall through to zig zig case */
treeRotate(root, tallerKid);
/* don't bother with other kid */
break;
}
}
}
}
/* free all the memory being used by the tree, and set the root to TREE_EMPTY */
static void treeDestroy(struct node **root) {
if (*root) { /*if the root exists*/
treeDestroy(&(*root)->child[LEFT]); /*recursively call on left*/
treeDestroy(&(*root)->child[RIGHT]); /*recursively call on right*/
free((*root)->key); /*free malloced mem for string in each node*/
free(*root); /*free memory for each node*/
*root = TREE_EMPTY; /*set root to empty*/
}
}
/*this function takes a pointer to an ordered set and frees all the memory of the tree that the ordered set has a pointer to
and the memory the orderedSet struct uses itself*/
void orderedSetDestroy (struct orderedSet *s) {
treeDestroy(&(s->set)); /*free tree in orderedSet struct*/
free(s); /*freeSet*/
}
/* insert an element into a tree pointed to by the root pointer, if the element
doesn't already exist there*/
static void treeInsert(struct node **root, char* newElement) {
struct node *e; /*node we're inserting*/
int equality; /*integer to store the results of strcmp*/
if ((*root) == TREE_EMPTY) { /*if nothing in the root, just insert newElement there*/
e = malloc(sizeof (struct node)); /*malloc memory for new node*/
assert(e); /*make sure malloc worked*/
e->key = newElement; /*set key of node to string*/
/*set children to null pointers*/
e->child[LEFT] = 0;
e->child[RIGHT] = 0;
/*update root to new element we just added*/
*root = e;
}
else { /*if tree wasn't empty --> need to find where in tree e needs to be inserted*/
equality = strcmp((*root)->key, newElement); /*store results of strcmp in equality*/
if (equality > 0) { /*this means the root > newElem --> need to insert in left subtree*/
treeInsert(&(*root)->child[LEFT], newElement);
}
if (equality < 0) { /*root < newElem --> right subtree*/
treeInsert(&(*root)->child[RIGHT], newElement);
}
if (equality == 0) { /*newElem already exists in tree --> need to free memory we're using for this string, don't insert it in tree*/
free(newElement);
}
}
/*fix data and rebalance on way out*/
treeFix(*root);
treeRebalance(root);
}
/*function that takes a string and returns a pointer to a newly malloced copy of that string*/
static char* myStrdup (const char* string) {
char* string2; /*new string*/
string2 = malloc(sizeof(char) * (strlen(string) + 1)); /*malloc appropriate amount of space for new string*/
assert(string2); /*make sure malloc worked*/
if (string2 != 0) {
strcpy(string2, string); /*copy input string to new string*/
}
return string2; /*returns new copied string or 0 if malloc failed*/
}
/*This function takes a pointer to an ordered set and a new string, and inserts the string into the tree pointed to in the ordered set*/
void orderedSetInsert(struct orderedSet *s, const char *newElem) {
char* insertElem; /*variable to store input string*/
insertElem = myStrdup(newElem); /*malloc space for input string*/
treeInsert(&(s->set), insertElem); /*insert new string into tree pointed to in orderedSet s*/
}
/*this function deletes the minimum string in a tree and returns its value.
Don't call on empty tree*/
static char* treeDeleteMin(struct node **root) {
struct node* toFree; /*pointer to node we need to delete/free*/
char* retString; /*string to return*/
assert(*root); /*make sure tree isn't empty*/
if ((*root)->child[LEFT]) { /*if there's a left child --> recurse again, not at minimum yet*/
retString = treeDeleteMin(&(*root)->child[LEFT]);
} else {/*if no left child --> reached minimum --> time to delete it*/
retString = (*root)->key; /*store return string value*/
toFree = *root; /*set toFree pointer to root node (node we want to delete)*/
*root = (*root)->child[RIGHT]; /*since removing this root, if it has a right child --> have root point to right child, otherwise, if no right child --> this node will just be set to 0*/
free(toFree); /*free memory for the node we're deleting*/
}
/*now that we've removed something --> need to fix data
and rebalance*/
treeFix(*root);
treeRebalance(root);
return retString;
}
/*This function takes in a pointer to a pointer to the root of a tree
and a target string and deletes the target string from the tree
if it exists there*/
static void treeDelete (struct node **root, const char* target) {
struct node *toFree; /*pointer to the node we're deleting/freeing*/
int equality; /*integer to store results of strcmp*/
if (*root) { /*if root exists*/
if((equality = strcmp((*root)->key, target)) == 0) { /*if the root and target are same*/
if ((*root)->child[RIGHT]) {
free((*root)->key); /*free key currently there, so we can set key to min of right child*/
(*root)->key = treeDeleteMin(&(*root)->child[RIGHT]);
} else { /*if no right child --> just make left child the new root*/
toFree = *root; /*set pointer to free node*/
*root = toFree->child[LEFT]; /*set new root to left child*/
free(toFree->key); /*free string in node we're deleting*/
free(toFree); /*free old root node*/
}
} else if (equality > 0) { /*root key > target --> look left*/
treeDelete(&(*root)->child[LEFT], target);
} else { /*root key < target --> look right*/
treeDelete(&(*root)->child[RIGHT], target);
}
/*fix height and size data in tree, then rebalance it after the deletion*/
treeFix(*root);
treeRebalance(root);
}
}
/*this function takes a pointer to an ordered set and string and
deletes it from the set if it exists in the set, otherwise it does
nothing*/
void orderedSetDelete(struct orderedSet *s, const char *elem) {
treeDelete(&(s->set), elem); /*deletes element from tree that orderedset struct has a pointer to*/
}
/*this function takes a pointer to an ordered set, a pointer to a root node, a function pointer and an argument pointer, and inserts
the key of the root node into the ordered set if the predicate called on arg and root->key is not zero*/
static void operateFilter(struct orderedSet *s, struct node *root, int (*predicate)(void *arg, const char *c), void *arg) {
if ((predicate(arg, root->key)) != 0) { /*make sure results of predicate function are not zero*/
orderedSetInsert(s, root->key); /*insert string into orderedSet*/
}
}
/*this function takes a pointer to an orderedSet, a pointer to a root, a function pointer and an argument pointer, and calls
operateFilter on every element in the tree that root points to, in increasing order*/
static void setFilter(struct orderedSet *s2, struct node *root, int (*predicate)(void *arg, const char* c), void *arg) {
if (root != 0) { /*make sure root exists*/
if(root->child[LEFT]) { /*if left child exists --> recursively call on it*/
setFilter(s2, root->child[LEFT], predicate, arg);
}
operateFilter(s2, root, predicate, arg); /*call operate filter on current node*/
if(root->child[RIGHT]) { /*if right child exists --> recursively call on it*/
setFilter(s2, root->child[RIGHT], predicate, arg);
}
}
}
/*this function takes a pointer to an ordered set, a function pointer and an argument pointer,
and returns a pointer to a new orderedSet, which contains all the strings in the initial orderedSet,
that when predicate was called on them, !=0*/
struct orderedSet *orderedSetFilter(const struct orderedSet *s, int (*predicate)(void *arg, const char* c), void *arg) {
struct orderedSet *s2; /*pointer to new ordered set*/
s2 = orderedSetCreate(); /*create the struct/malloc memory for it*/
setFilter(s2, s->set, predicate, arg); /*call predicate on every element in s in increasing order, and insert the key into the new ordered set if results !=0*/
return s2; /*return pointer to new ordered set*/
}