-
Notifications
You must be signed in to change notification settings - Fork 0
/
psb_bag.c
477 lines (425 loc) · 15.9 KB
/
psb_bag.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
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
/* FILE psb_bag.c
* Implementation of the bag ADT using an psb tree.
* Author: Tommy Pearson and Oliver Liang, March 2012.
*/
/******************************************************************************
* Types and Constants. *
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "bag.h"
#define RIGHT_CHILD 1
#define LEFT_CHILD 0
#define NO_ANCESTOR 2
/* TYPE psb_node_t -- A node in an psb tree. */
typedef struct psb_node {
bag_elem_t elem; /* the element stored in this node */
struct psb_node *left; /* pointer to this node's left child */
struct psb_node *right; /* pointer to this node's right child */
} psb_node_t;
/* TYPE struct bag -- Definition of struct bag from the header. */
struct bag {
size_t size; /* number of elements in this bag */
psb_node_t *root; /* root of the psb tree storing the elements */
int (*cmp)(bag_elem_t, bag_elem_t); /* function to compare elements */
};
/******************************************************************************
* Declarations of helper functions -- including full documentation. *
******************************************************************************/
/* FUNCTION psb_destroy
* Free the memory allocated for the binary tree rooted at a given node.
* Parameters and preconditions:
* root: the root of the tree to free
* Return value: none
* Side-effects:
* all the memory allocated for nodes in the subtree rooted at root has been
* freed
*/
static
void psb_destroy(psb_node_t *root);
/* FUNCTION psb_traverse
* Call a function on every element in a BST, given its root.
* Parameters and preconditions:
* root: the root of the BST to traverse
* fun != NULL: a pointer to a function to apply to each element in the tree
* Return value: none
* Side-effect:
* function fun has been called on each element in the tree rooted at root,
* in order
*/
static
void psb_traverse(const psb_node_t *root, void (*fun)(bag_elem_t));
/* FUNCTION psb_contains
* Return whether or not a BST contains a certain element, given the root.
* Parameters and preconditions:
* root: the root of the BST to search
* elem != NULL: the element to search for
* cmp != NULL: the comparison function to use for the search
* is_right == NO_ANCESTOR (!=1 && !=0): a variable used in the recursive calls
* parent == NULL: a variable used in the recursive calls
* is_parent_right == NO_ANCESTOR (!=1 && !=0):
* a variable used in the recursive calls
* grandparent == NULL: a variable used in the recursive calls
* bag != NULL: a pointer to the bag being searched
* Return value:
* elem, if the BST rooted at 'root' contains it; NULL otherwise
* Side-effects: If the element is found, a rotation is done about its parent
* so that the the element moves closer to the root
*/
static
bag_elem_t psb_contains(const psb_node_t *root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t),
int is_right, psb_node_t *parent,
int is_parent_right,
psb_node_t *grandparent,
struct bag *bag);
/* FUNCTION psb_insert
* Add an element to a BST, given a pointer to its root.
* Parameters and preconditions:
* root: a pointer to the root of the BST into which to insert
* elem != NULL: the element to insert
* cmp != NULL: the comparison function to use to find the insertion point
* Return value:
* elem, if it was inserted; NULL in case of error
* Side-effects:
* memory has been allocated for the new element, and the element has been
* added at the bottom
*/
static
bag_elem_t psb_insert(psb_node_t **root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t));
/* FUNCTION psb_remove
* Remove an element from a BST, given a pointer to its root.
* Parameters and preconditions:
* root: a pointer to the root of the BST into which to remove
* elem != NULL: the element to remove
* cmp != NULL: the comparison function to use to find the removal point
* Return value:
* elem, if it was removed; NULL if the element was not there
* Side-effects:
* memory has been freed for the element removed, and the tree structure has
* been adjusted accordingly
*/
static
bag_elem_t psb_remove(psb_node_t **root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t));
/* FUNCTION psb_remove_min
* Remove and return the smallest element in a BST, given a pointer to its
* root.
* Parameters and preconditions:
* root: a pointer to the root of the BST
* Return value:
* the smallest element in the BST rooted at 'root'
* Side-effects:
* memory has been freed for the node containing the smallest element
*/
static
bag_elem_t psb_remove_min(psb_node_t **root);
/* FUNCTION psb_remove_max
* Remove and return the largest element in a BST, given a pointer to its
* root.
* Parameters and preconditions:
* root: a pointer to the root of the BST
* Return value:
* the largest element in the BST rooted at 'root'
* Side-effects:
* memory has been freed for the node containing the largest element
*/
static
bag_elem_t psb_remove_max(psb_node_t **root);
/* FUNCTION psb_rotate_to_the_left
* Perform a single rotation of *parent to the left -- the tree structure
* goes from *parent to child
* / \ / \
* A child *parent C
* / \ / \
* B C A B
* Parameters and precondition:
* parent != NULL: a pointer to the root of the tree to rotate
* (*parent != NULL and (*parent)->right != NULL)
* Return value: none
* Side-effects:
* the subtree rooted at *parent has been modified by rotating *parent with
* its right child
*/
static
void psb_rotate_to_the_left(psb_node_t **parent);
/* psb_rotate_to_the_right
* Perform a single rotation of *parent to the right -- the tree structure
* goes from *parent to child
* / \ / \
* child C A *parent
* / \ / \
* A B B C
* Parameters and precondition:
* parent != NULL: a pointer to the root of the tree to rotate
* (*parent != NULL and (*parent)->left != NULL)
* Return value: none
* Side-effects:
* the subtree rooted at *parent has been modified by rotating *parent with
* its left child
*/
static
void psb_rotate_to_the_right(psb_node_t **parent);
/* FUNCTION psb_node_create
* Create a new psb_node.
* Parameters and preconditions:
* elem: the element to store in the new node
* Return value:
* pointer to a new node that stores elem and whose children are both NULL;
* NULL in case of error with memory allocation
* Side-effects:
* memory has been allocated for the new node
*/
static
psb_node_t *psb_node_create(bag_elem_t elem);
/******************************************************************************
* Definitions of "public" functions -- see header file for documentation. *
******************************************************************************/
bag_t *bag_create(int (*cmp)(bag_elem_t, bag_elem_t))
{
bag_t *bag = malloc(sizeof(bag_t));
if (bag) {
bag->size = 0;
bag->root = NULL;
bag->cmp = cmp;
}
return bag;
}
void bag_destroy(bag_t *bag)
{
psb_destroy(bag->root);
free(bag);
}
size_t bag_size(const bag_t *bag)
{
return bag->size;
}
void bag_traverse(const bag_t *bag, void (*fun)(bag_elem_t))
{
psb_traverse(bag->root, fun);
}
bag_elem_t bag_contains(bag_t *bag, bag_elem_t elem)
{
return psb_contains(bag->root, elem, bag->cmp, NO_ANCESTOR,
NULL, NO_ANCESTOR, NULL, bag);
}
bag_elem_t bag_insert(bag_t *bag, bag_elem_t elem)
{
bag_elem_t e = psb_insert(&bag->root, elem, bag->cmp);
if (e) bag->size++;
return e;
}
bag_elem_t bag_remove(bag_t *bag, bag_elem_t elem)
{
bag_elem_t e = psb_remove(&bag->root, elem, bag->cmp);
if (e) bag->size--;
return e;
}
/******************************************************************************
* Definitions of helper functions -- see above for documentation. *
******************************************************************************/
void psb_destroy(psb_node_t *root)
{
if (root) {
psb_destroy(root->left);
psb_destroy(root->right);
free(root);
}
}
void psb_traverse(const psb_node_t *root, void (*fun)(bag_elem_t))
{
if (root) {
psb_traverse(root->left, fun);
(*fun)(root->elem);
psb_traverse(root->right, fun);
}
}
/* In order to perform a rotation within the contains function,
* information on the parent, and which child (left or right),
* need to be passed into the function. In order to 'catch' the
* rotation properly, information on the grandparent and which
* child the element is found in also need to be passed recursively.
* In the event that the element is at the second level, the rotation
* needs to be 'caught' by the root of the bag, which is why the bag
* is passed in as a parameter.
*/
bag_elem_t psb_contains(const psb_node_t *root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t),
int is_right, psb_node_t *parent,
int is_parent_right,
psb_node_t *grandparent,
struct bag *bag)
{
if (! root)
return NULL;
else if ((*cmp)(elem, root->elem) < 0)
return psb_contains(root->left, elem, cmp, LEFT_CHILD,
root, is_right, parent, bag);
else if ((*cmp)(elem, root->elem) > 0)
return psb_contains(root->right, elem, cmp, RIGHT_CHILD,
root, is_right, parent, bag);
else /* ((*cmp)(elem, root->elem) == 0) */
// Have the grandparent point to the root
if (is_parent_right == RIGHT_CHILD){
grandparent->right = root;
}else if(! is_parent_right){ //parent is a left child
grandparent->left = root;
/* The root is at the second level and has no grandparent.
the element must become the root of the entire tree.
Also handles the case of the element being at the root*/
}else bag->root = root;
/* Perform a rotation to move the element found closer
to the root */
if (is_right == RIGHT_CHILD) psb_rotate_to_the_left(&parent);
// If root is a left child
else if (! is_right) psb_rotate_to_the_right(&parent);
return root->elem;
}
bag_elem_t psb_insert(psb_node_t **root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t))
{
bag_elem_t inserted;
if (! *root) {
if ((*root = psb_node_create(elem)))
inserted = (*root)->elem;
else
inserted = NULL;
} else if ((*cmp)(elem, (*root)->elem) < 0) {
(inserted = psb_insert(&(*root)->left, elem, cmp));
/* The tree does not get rebalanced at this point */
} else if ((*cmp)(elem, (*root)->elem) > 0) {
(inserted = psb_insert(&(*root)->right, elem, cmp));
} else { /* ((*cmp)(elem, (*root)->elem) == 0) */
/* Insert into the left subtree */
inserted = psb_insert(&(*root)->left, elem, cmp);
}
return inserted;
}
bag_elem_t psb_remove(psb_node_t **root, bag_elem_t elem,
int (*cmp)(bag_elem_t, bag_elem_t))
{
bag_elem_t removed;
if (! *root) {
removed = NULL;
} else if ((*cmp)(elem, (*root)->elem) < 0) {
(removed = psb_remove(&(*root)->left, elem, cmp));
/* The subtree does not get rebalanced */
} else if ((*cmp)(elem, (*root)->elem) > 0) {
(removed = psb_remove(&(*root)->right, elem, cmp));
/* The subtree does not get rebalanced */
} else { /* ((*cmp)(elem, (*root)->elem) == 0) */
removed = (*root)->elem;
if ((*root)->left && (*root)->right) {
/* Remove from the left subtree */
(*root)->elem = psb_remove_max(&(*root)->left);
} else {
/* Remove *root. */
psb_node_t *old = *root;
*root = (*root)->left ? (*root)->left : (*root)->right;
free(old);
}
}
return removed;
}
bag_elem_t psb_remove_min(psb_node_t **root)
{
bag_elem_t min;
if ((*root)->left) {
/* *root is not the minimum, keep going */
min = psb_remove_min(&(*root)->left);
} else {
/* Remove *root. */
psb_node_t *old = *root;
min = (*root)->elem;
*root = (*root)->right;
free(old);
}
return min;
}
bag_elem_t psb_remove_max(psb_node_t **root)
{
bag_elem_t max;
if ((*root)->right) {
/* *root is not the maximum, keep going and rebalance if necessary. */
max = psb_remove_max(&(*root)->right);
} else {
/* Remove *root. */
psb_node_t *old = *root;
max = (*root)->elem;
*root = (*root)->left;
free(old);
}
return max;
}
void psb_rotate_to_the_left(psb_node_t **parent)
{
/* Rearrange pointers. */
psb_node_t *child = (*parent)->right;
(*parent)->right = child->left;
child->left = *parent;
*parent = child;
}
void psb_rotate_to_the_right(psb_node_t **parent)
{
/* Rearrange pointers. */
psb_node_t *child = (*parent)->left;
(*parent)->left = child->right;
child->right = *parent;
*parent = child;
}
psb_node_t *psb_node_create(bag_elem_t elem)
{
psb_node_t *node = malloc(sizeof(psb_node_t));
if (node) {
node->elem = elem;
node->left = NULL;
node->right = NULL;
}
return node;
}
/******************************************************************************
* Additional "hidden" functions, for debugging purposes. *
******************************************************************************/
/* FUNCTION psb_print
* Print every value in the subtree rooted at root to stdout, in a "sideways
* tree" layout with the root at the given depth. Print each node's element.
* Parameters and preconditions:
* root != NULL: the root of the subtree to print
* depth >= 0: the depth at which to print the root's value
* indent > 0: number of spaces to print for each level of depth
* print != NULL: the function to use to print each node's value
* Return value: none
* Side-effects:
* every value in the subtree rooted at root is printed to stdout, using a
* "sideways tree" layout (with right subtrees above and left subtrees below,
* and indentation to indicate each value's depth in the tree)
*/
static
void psb_print(const psb_node_t *root, int depth, int indent,
void (*print)(bag_elem_t))
{
if (root) {
psb_print(root->right, depth + 1, indent, print);
/* Print each value followed by its depth, with INDENT spaces of
* indentation for each level of depth in the tree. */
printf("%*s", depth * indent, "");
(*print)(root->elem);
psb_print(root->left, depth + 1, indent, print);
}
}
/* FUNCTION bag_print
* Print every value in a bag to stdout, in a "sideways tree" layout.
* Parameters and preconditions:
* bag != NULL: the bag
* print != NULL: the function to use to print each value in the bag
* Return value: none
* Side-effects:
* every value in the bag is printed to stdout, using a "sideways tree"
* layout (with right subtrees above and left subtrees below, and indentation
* to indicate each value's depth in the tree)
*/
void bag_print(const bag_t *bag, int indent, void (*print)(bag_elem_t))
{
psb_print(bag->root, 1, indent, print);
}