source: trunk/src/zAVLTree.c@ 453

Last change on this file since 453 was 452, checked in by katerina, 10 years ago

Fix for ticket #353 (multiple exclusions for SUID check).

File size: 13.7 KB
Line 
1/*
2 * zAVLTree.c: Source code for zAVLTrees.
3 * Copyright (C) 1998,2001 Michael H. Buselli
4 * This is version 0.1.3 (alpha).
5 * Generated from $Id: xAVLTree.c.sh,v 1.5 2001/06/07 06:58:28 cosine Exp $
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * The author of this library can be reached at the following address:
22 * Michael H. Buselli
23 * 30051 N. Waukegan Rd. Apt. 103
24 * Lake Bluff, IL 60044-5412
25 *
26 * Or you can send email to <cosine@cosine.org>.
27 * The official web page for this product is:
28 * http://www.cosine.org/project/AVLTree/
29 */
30
31#include <stdlib.h>
32#include <string.h>
33#include "zAVLTree.h"
34
35/* Interface for handling "string only" items rw 2014-06-26
36 */
37static zAVLKey zstring_key (void const * arg)
38{
39 return (zAVLKey) arg;
40}
41static void zfree_string (void * inptr)
42{
43 char * str = (char *) inptr;
44 str[0] = '\0';
45 free (str);
46 return;
47}
48void zAVL_string_reset (zAVLTree * tree)
49{
50 if (tree)
51 zAVLFreeTree (tree, zfree_string);
52 return;
53}
54int zAVL_string_set (zAVLTree ** tree, const char * key)
55{
56 if (tree && key)
57 {
58 zAVLTree * itree = (*tree);
59 if (!itree)
60 {
61 itree = zAVLAllocTree (zstring_key, zAVL_KEY_STRING);
62 if (!itree)
63 {
64 return -1;
65 }
66 }
67 *tree = itree;
68 return zAVLInsert (itree, strdup(key));
69 }
70 return -1;
71}
72char * zAVL_string_get (zAVLTree * tree, char * key)
73{
74 /* zAVLSearch() checks for NULL tree
75 */
76 if (key)
77 {
78 return ((char *) zAVLSearch (tree, key));
79 }
80 return NULL;
81}
82
83
84/* Wed Nov 23 17:57:42 CET 2005 rw: introduce third argument in
85 * zAVLCloseSearchNode() to avoid redundant strcmp
86 */
87static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
88 int * ok);
89static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode);
90static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item));
91static void zAVLFillVacancy (zAVLTree *avltree,
92 zAVLNode *origparent, zAVLNode **superparent,
93 zAVLNode *left, zAVLNode *right);
94
95#define MAX(x, y) ((x) > (y) ? (x) : (y))
96#define MIN(x, y) ((x) < (y) ? (x) : (y))
97#define L_DEPTH(n) ((n)->left ? (n)->left->depth : 0)
98#define R_DEPTH(n) ((n)->right ? (n)->right->depth : 0)
99#define CALC_DEPTH(n) (MAX(L_DEPTH(n), R_DEPTH(n)) + 1)
100
101#define ZAVL_OK 1
102#define ZAVL_NO 0
103
104/* The comparison function. Was a macro, but this allows for more
105 * flexibility (non-string keys). The key is a (void *) now, and
106 * the type is stored in the zAVLTree struct. Oct 21, 2011, rw
107 */
108static int zAVLKey_cmp(const zAVLTree * tree, zAVLKey a, zAVLKey b)
109{
110 if (tree->keytype == zAVL_KEY_STRING)
111 {
112 return (strcmp((char*)a, (char *)b));
113 }
114 else /* zAVL_KEY_INT */
115 {
116 int x = *((int *)a);
117 int y = *((int *)b);
118
119 if (x > y) return 1;
120 else if (x < y) return -1;
121 else return 0;
122 }
123}
124
125/*
126 * AVLAllocTree:
127 * Allocate memory for a new AVL tree and set the getkey function for
128 * that tree. The getkey function should take an item and return an
129 * AVLKey that is to be used for indexing this object in the AVL tree.
130 * On success, a pointer to the malloced AVLTree is returned. If there
131 * was a malloc failure, then NULL is returned.
132 */
133zAVLTree *zAVLAllocTree (zAVLKey (*getkey)(void const *item), int keytype)
134{
135 zAVLTree *rc;
136
137 rc = calloc(1, sizeof(zAVLTree));
138 if (rc == NULL)
139 return NULL;
140
141 rc->top = NULL;
142 rc->count = 0;
143 rc->getkey = getkey;
144 rc->keytype = keytype;
145 return rc;
146}
147
148
149/*
150 * AVLFreeTree:
151 * Free all memory used by this AVL tree. If freeitem is not NULL, then
152 * it is assumed to be a destructor for the items reference in the AVL
153 * tree, and they are deleted as well.
154 */
155void zAVLFreeTree (zAVLTree *avltree, void (freeitem)(void *item))
156{
157 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
158 return;
159 if (avltree->top)
160 zAVLFreeBranch(avltree->top, freeitem);
161 free(avltree);
162}
163
164
165/*
166 * AVLInsert:
167 * Create a new node and insert an item there.
168 *
169 * Returns 0 on success,
170 * -1 on malloc failure,
171 * 3 if duplicate key.
172 */
173int zAVLInsert (zAVLTree *avltree, void *item)
174{
175 zAVLNode *newnode;
176 zAVLNode *node;
177 zAVLNode *balnode;
178 zAVLNode *nextbalnode;
179 int ok;
180
181 newnode = calloc(1, sizeof(zAVLNode));
182 if (newnode == NULL)
183 return -1;
184
185 newnode->key = avltree->getkey(item);
186 newnode->item = item;
187 newnode->depth = 1;
188 newnode->left = NULL;
189 newnode->right = NULL;
190 newnode->parent = NULL;
191
192 if (avltree->top != NULL) {
193 node = zAVLCloseSearchNode(avltree, newnode->key, &ok);
194
195 if (ok == ZAVL_OK) { /* exists already */
196 free(newnode);
197 return 3;
198 }
199
200 newnode->parent = node;
201
202 if (zAVLKey_cmp(avltree, newnode->key, node->key) < 0) {
203 node->left = newnode;
204 node->depth = CALC_DEPTH(node);
205 }
206
207 else {
208 node->right = newnode;
209 node->depth = CALC_DEPTH(node);
210 }
211
212 for (balnode = node->parent; balnode; balnode = nextbalnode) {
213 nextbalnode = balnode->parent;
214 zAVLRebalanceNode(avltree, balnode);
215 }
216 }
217
218 else {
219 avltree->top = newnode;
220 }
221
222 avltree->count++;
223 return 0;
224}
225
226
227/*
228 * zAVLSearch:
229 * Return a pointer to the item with the given key in the AVL tree. If
230 * no such item is in the tree, then NULL is returned.
231 */
232void *zAVLSearch (zAVLTree const *avltree, zAVLKey key)
233{
234 zAVLNode *node;
235 int ok;
236
237 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
238 return NULL;
239
240 node = zAVLCloseSearchNode(avltree, key, &ok);
241
242 if (node && ok == ZAVL_OK)
243 return node->item;
244
245 return NULL;
246}
247
248
249/*
250 * zAVLDelete:
251 * Deletes the node with the given key. Does not delete the item at
252 * that key. Returns 0 on success and -1 if a node with the given key
253 * does not exist.
254 */
255int zAVLDelete (zAVLTree *avltree, zAVLKey key)
256{
257 zAVLNode *avlnode;
258 zAVLNode *origparent;
259 zAVLNode **superparent;
260 int ok;
261
262 avlnode = zAVLCloseSearchNode(avltree, key, &ok);
263 if (avlnode == NULL || ok == ZAVL_NO) /* does not exist */
264 return -1;
265
266 origparent = avlnode->parent;
267
268 if (origparent) {
269 if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
270 superparent = &(avlnode->parent->left);
271 else
272 superparent = &(avlnode->parent->right);
273 }
274 else
275 superparent = &(avltree->top);
276
277 zAVLFillVacancy(avltree, origparent, superparent,
278 avlnode->left, avlnode->right);
279 free(avlnode);
280 avltree->count--;
281 return 0;
282}
283
284
285/*
286 * zAVLFirst:
287 * Initializes an zAVLCursor object and returns the item with the lowest
288 * key in the zAVLTree.
289 */
290void *zAVLFirst (zAVLCursor *avlcursor, zAVLTree const *avltree)
291{
292 const zAVLNode *avlnode;
293
294 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
295 return NULL;
296
297 avlcursor->avltree = avltree;
298
299 if (avltree->top == NULL) {
300 avlcursor->curnode = NULL;
301 return NULL;
302 }
303
304 for (avlnode = avltree->top;
305 avlnode->left != NULL;
306 avlnode = avlnode->left);
307 avlcursor->curnode = avlnode;
308 return avlnode->item;
309}
310
311
312/*
313 * zAVLNext:
314 * Called after an zAVLFirst() call, this returns the item with the least
315 * key that is greater than the last item returned either by zAVLFirst()
316 * or a previous invokation of this function.
317 */
318void *zAVLNext (zAVLCursor *avlcursor)
319{
320 const zAVLNode *avlnode;
321
322 avlnode = avlcursor->curnode;
323
324 if (avlnode->right != NULL) {
325 for (avlnode = avlnode->right;
326 avlnode->left != NULL;
327 avlnode = avlnode->left);
328 avlcursor->curnode = avlnode;
329 return avlnode->item;
330 }
331
332 while (avlnode->parent && avlnode->parent->left != avlnode) {
333 avlnode = avlnode->parent;
334 }
335
336 if (avlnode->parent == NULL) {
337 avlcursor->curnode = NULL;
338 return NULL;
339 }
340
341 avlcursor->curnode = avlnode->parent;
342 return avlnode->parent->item;
343}
344
345
346/*
347 * zAVLCloseSearchNode:
348 * Return a pointer to the node closest to the given key.
349 * Returns NULL if the AVL tree is empty.
350 */
351static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
352 int * ok)
353{
354 zAVLNode *node;
355
356 *ok = ZAVL_NO;
357
358 node = avltree->top;
359
360 if (!node)
361 return NULL;
362
363 for (;;) {
364 if (!zAVLKey_cmp(avltree, node->key, key))
365 {
366 *ok = ZAVL_OK;
367 return node;
368 }
369
370 if (zAVLKey_cmp(avltree, node->key, key) < 0) {
371 if (node->right)
372 node = node->right;
373 else
374 return node;
375 }
376
377 else {
378 if (node->left)
379 node = node->left;
380 else
381 return node;
382 }
383 }
384}
385
386
387/*
388 * zAVLRebalanceNode:
389 * Rebalances the AVL tree if one side becomes too heavy. This function
390 * assumes that both subtrees are AVL trees with consistant data. This
391 * function has the additional side effect of recalculating the depth of
392 * the tree at this node. It should be noted that at the return of this
393 * function, if a rebalance takes place, the top of this subtree is no
394 * longer going to be the same node.
395 */
396static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode)
397{
398 long depthdiff;
399 zAVLNode *child;
400 zAVLNode *gchild;
401 zAVLNode *origparent;
402 zAVLNode **superparent;
403
404 origparent = avlnode->parent;
405
406 if (origparent) {
407 if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
408 superparent = &(avlnode->parent->left);
409 else
410 superparent = &(avlnode->parent->right);
411 }
412 else
413 superparent = &(avltree->top);
414
415 depthdiff = R_DEPTH(avlnode) - L_DEPTH(avlnode);
416
417 if (depthdiff <= -2 && avlnode->left) {
418 child = avlnode->left;
419
420 if (L_DEPTH(child) >= R_DEPTH(child)) {
421 avlnode->left = child->right;
422 if (avlnode->left != NULL)
423 avlnode->left->parent = avlnode;
424 avlnode->depth = CALC_DEPTH(avlnode);
425 child->right = avlnode;
426 if (child->right != NULL)
427 child->right->parent = child;
428 child->depth = CALC_DEPTH(child);
429 *superparent = child;
430 child->parent = origparent;
431 }
432
433 else {
434 gchild = child->right;
435 if (gchild)
436 {
437 avlnode->left = gchild->right;
438 if (avlnode->left != NULL)
439 avlnode->left->parent = avlnode;
440 avlnode->depth = CALC_DEPTH(avlnode);
441 child->right = gchild->left;
442 if (child->right != NULL)
443 child->right->parent = child;
444 child->depth = CALC_DEPTH(child);
445 gchild->right = avlnode;
446 if (gchild->right != NULL)
447 gchild->right->parent = gchild;
448 gchild->left = child;
449 if (gchild->left != NULL)
450 gchild->left->parent = gchild;
451 gchild->depth = CALC_DEPTH(gchild);
452 *superparent = gchild;
453 gchild->parent = origparent;
454 }
455 }
456 }
457
458 else if (depthdiff >= 2 && avlnode->right) {
459 child = avlnode->right;
460
461 if (R_DEPTH(child) >= L_DEPTH(child)) {
462 avlnode->right = child->left;
463 if (avlnode->right != NULL)
464 avlnode->right->parent = avlnode;
465 avlnode->depth = CALC_DEPTH(avlnode);
466 child->left = avlnode;
467 if (child->left != NULL)
468 child->left->parent = child;
469 child->depth = CALC_DEPTH(child);
470 *superparent = child;
471 child->parent = origparent;
472 }
473
474 else {
475 gchild = child->left;
476 if (gchild)
477 {
478 avlnode->right = gchild->left;
479 if (avlnode->right != NULL)
480 avlnode->right->parent = avlnode;
481 avlnode->depth = CALC_DEPTH(avlnode);
482 child->left = gchild->right;
483 if (child->left != NULL)
484 child->left->parent = child;
485 child->depth = CALC_DEPTH(child);
486 gchild->left = avlnode;
487 if (gchild->left != NULL)
488 gchild->left->parent = gchild;
489 gchild->right = child;
490 if (gchild->right != NULL)
491 gchild->right->parent = gchild;
492 gchild->depth = CALC_DEPTH(gchild);
493 *superparent = gchild;
494 gchild->parent = origparent;
495 }
496 }
497 }
498
499 else {
500 avlnode->depth = CALC_DEPTH(avlnode);
501 }
502}
503
504
505/*
506 * zAVLFreeBranch:
507 * Free memory used by this node and its item. If the freeitem argument
508 * is not NULL, then that function is called on the items to free their
509 * memory as well. In other words, the freeitem function is a
510 * destructor for the items in the tree.
511 */
512static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item))
513{
514 if (avlnode->left)
515 zAVLFreeBranch(avlnode->left, freeitem);
516 if (avlnode->right)
517 zAVLFreeBranch(avlnode->right, freeitem);
518 if (freeitem)
519 freeitem(avlnode->item);
520 free(avlnode);
521}
522
523
524/*
525 * zAVLFillVacancy:
526 * Given a vacancy in the AVL tree by it's parent, children, and parent
527 * component pointer, fill that vacancy.
528 */
529static void zAVLFillVacancy (zAVLTree *avltree,
530 zAVLNode *origparent, zAVLNode **superparent,
531 zAVLNode *left, zAVLNode *right)
532{
533 zAVLNode *avlnode;
534 zAVLNode *balnode;
535 zAVLNode *nextbalnode;
536
537 if (left == NULL) {
538 if (right)
539 right->parent = origparent;
540
541 *superparent = right;
542 balnode = origparent;
543 }
544
545 else {
546 for (avlnode = left; avlnode->right != NULL; avlnode = avlnode->right);
547
548 if (avlnode == left) {
549 balnode = avlnode;
550 }
551 else {
552 balnode = avlnode->parent;
553 balnode->right = avlnode->left;
554 if (balnode->right != NULL)
555 balnode->right->parent = balnode;
556 avlnode->left = left;
557 left->parent = avlnode;
558 }
559
560 avlnode->right = right;
561 if (right != NULL)
562 right->parent = avlnode;
563 *superparent = avlnode;
564 avlnode->parent = origparent;
565 }
566
567 for (; balnode; balnode = nextbalnode) {
568 nextbalnode = balnode->parent;
569 zAVLRebalanceNode(avltree, balnode);
570 }
571}
Note: See TracBrowser for help on using the repository browser.