source: trunk/src/zAVLTree.c@ 460

Last change on this file since 460 was 458, checked in by katerina, 10 years ago

Fix for ticket #358 (repetitive lstat warning) and #359 (reporting of added/deleted top level directories).

File size: 14.0 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, const 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}
82void zAVL_string_del (zAVLTree * tree, const char * key)
83{
84 /* zAVLSearch() checks for NULL tree
85 */
86 if (key)
87 {
88 char * item = ((char *) zAVLSearch (tree, key));
89 if (item)
90 {
91 zAVLDelete(tree, key);
92 zfree_string(item);
93 }
94 }
95 return;
96}
97
98
99
100/* Wed Nov 23 17:57:42 CET 2005 rw: introduce third argument in
101 * zAVLCloseSearchNode() to avoid redundant strcmp
102 */
103static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
104 int * ok);
105static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode);
106static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item));
107static void zAVLFillVacancy (zAVLTree *avltree,
108 zAVLNode *origparent, zAVLNode **superparent,
109 zAVLNode *left, zAVLNode *right);
110
111#define MAX(x, y) ((x) > (y) ? (x) : (y))
112#define MIN(x, y) ((x) < (y) ? (x) : (y))
113#define L_DEPTH(n) ((n)->left ? (n)->left->depth : 0)
114#define R_DEPTH(n) ((n)->right ? (n)->right->depth : 0)
115#define CALC_DEPTH(n) (MAX(L_DEPTH(n), R_DEPTH(n)) + 1)
116
117#define ZAVL_OK 1
118#define ZAVL_NO 0
119
120/* The comparison function. Was a macro, but this allows for more
121 * flexibility (non-string keys). The key is a (void *) now, and
122 * the type is stored in the zAVLTree struct. Oct 21, 2011, rw
123 */
124static int zAVLKey_cmp(const zAVLTree * tree, zAVLKey a, zAVLKey b)
125{
126 if (tree->keytype == zAVL_KEY_STRING)
127 {
128 return (strcmp((char*)a, (char *)b));
129 }
130 else /* zAVL_KEY_INT */
131 {
132 int x = *((int *)a);
133 int y = *((int *)b);
134
135 if (x > y) return 1;
136 else if (x < y) return -1;
137 else return 0;
138 }
139}
140
141/*
142 * AVLAllocTree:
143 * Allocate memory for a new AVL tree and set the getkey function for
144 * that tree. The getkey function should take an item and return an
145 * AVLKey that is to be used for indexing this object in the AVL tree.
146 * On success, a pointer to the malloced AVLTree is returned. If there
147 * was a malloc failure, then NULL is returned.
148 */
149zAVLTree *zAVLAllocTree (zAVLKey (*getkey)(void const *item), int keytype)
150{
151 zAVLTree *rc;
152
153 rc = calloc(1, sizeof(zAVLTree));
154 if (rc == NULL)
155 return NULL;
156
157 rc->top = NULL;
158 rc->count = 0;
159 rc->getkey = getkey;
160 rc->keytype = keytype;
161 return rc;
162}
163
164
165/*
166 * AVLFreeTree:
167 * Free all memory used by this AVL tree. If freeitem is not NULL, then
168 * it is assumed to be a destructor for the items reference in the AVL
169 * tree, and they are deleted as well.
170 */
171void zAVLFreeTree (zAVLTree *avltree, void (freeitem)(void *item))
172{
173 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
174 return;
175 if (avltree->top)
176 zAVLFreeBranch(avltree->top, freeitem);
177 free(avltree);
178}
179
180
181/*
182 * AVLInsert:
183 * Create a new node and insert an item there.
184 *
185 * Returns 0 on success,
186 * -1 on malloc failure,
187 * 3 if duplicate key.
188 */
189int zAVLInsert (zAVLTree *avltree, void *item)
190{
191 zAVLNode *newnode;
192 zAVLNode *node;
193 zAVLNode *balnode;
194 zAVLNode *nextbalnode;
195 int ok;
196
197 newnode = calloc(1, sizeof(zAVLNode));
198 if (newnode == NULL)
199 return -1;
200
201 newnode->key = avltree->getkey(item);
202 newnode->item = item;
203 newnode->depth = 1;
204 newnode->left = NULL;
205 newnode->right = NULL;
206 newnode->parent = NULL;
207
208 if (avltree->top != NULL) {
209 node = zAVLCloseSearchNode(avltree, newnode->key, &ok);
210
211 if (ok == ZAVL_OK) { /* exists already */
212 free(newnode);
213 return 3;
214 }
215
216 newnode->parent = node;
217
218 if (zAVLKey_cmp(avltree, newnode->key, node->key) < 0) {
219 node->left = newnode;
220 node->depth = CALC_DEPTH(node);
221 }
222
223 else {
224 node->right = newnode;
225 node->depth = CALC_DEPTH(node);
226 }
227
228 for (balnode = node->parent; balnode; balnode = nextbalnode) {
229 nextbalnode = balnode->parent;
230 zAVLRebalanceNode(avltree, balnode);
231 }
232 }
233
234 else {
235 avltree->top = newnode;
236 }
237
238 avltree->count++;
239 return 0;
240}
241
242
243/*
244 * zAVLSearch:
245 * Return a pointer to the item with the given key in the AVL tree. If
246 * no such item is in the tree, then NULL is returned.
247 */
248void *zAVLSearch (zAVLTree const *avltree, zAVLKey key)
249{
250 zAVLNode *node;
251 int ok;
252
253 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
254 return NULL;
255
256 node = zAVLCloseSearchNode(avltree, key, &ok);
257
258 if (node && ok == ZAVL_OK)
259 return node->item;
260
261 return NULL;
262}
263
264
265/*
266 * zAVLDelete:
267 * Deletes the node with the given key. Does not delete the item at
268 * that key. Returns 0 on success and -1 if a node with the given key
269 * does not exist.
270 */
271int zAVLDelete (zAVLTree *avltree, zAVLKey key)
272{
273 zAVLNode *avlnode;
274 zAVLNode *origparent;
275 zAVLNode **superparent;
276 int ok;
277
278 avlnode = zAVLCloseSearchNode(avltree, key, &ok);
279 if (avlnode == NULL || ok == ZAVL_NO) /* does not exist */
280 return -1;
281
282 origparent = avlnode->parent;
283
284 if (origparent) {
285 if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
286 superparent = &(avlnode->parent->left);
287 else
288 superparent = &(avlnode->parent->right);
289 }
290 else
291 superparent = &(avltree->top);
292
293 zAVLFillVacancy(avltree, origparent, superparent,
294 avlnode->left, avlnode->right);
295 free(avlnode);
296 avltree->count--;
297 return 0;
298}
299
300
301/*
302 * zAVLFirst:
303 * Initializes an zAVLCursor object and returns the item with the lowest
304 * key in the zAVLTree.
305 */
306void *zAVLFirst (zAVLCursor *avlcursor, zAVLTree const *avltree)
307{
308 const zAVLNode *avlnode;
309
310 if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
311 return NULL;
312
313 avlcursor->avltree = avltree;
314
315 if (avltree->top == NULL) {
316 avlcursor->curnode = NULL;
317 return NULL;
318 }
319
320 for (avlnode = avltree->top;
321 avlnode->left != NULL;
322 avlnode = avlnode->left);
323 avlcursor->curnode = avlnode;
324 return avlnode->item;
325}
326
327
328/*
329 * zAVLNext:
330 * Called after an zAVLFirst() call, this returns the item with the least
331 * key that is greater than the last item returned either by zAVLFirst()
332 * or a previous invokation of this function.
333 */
334void *zAVLNext (zAVLCursor *avlcursor)
335{
336 const zAVLNode *avlnode;
337
338 avlnode = avlcursor->curnode;
339
340 if (avlnode->right != NULL) {
341 for (avlnode = avlnode->right;
342 avlnode->left != NULL;
343 avlnode = avlnode->left);
344 avlcursor->curnode = avlnode;
345 return avlnode->item;
346 }
347
348 while (avlnode->parent && avlnode->parent->left != avlnode) {
349 avlnode = avlnode->parent;
350 }
351
352 if (avlnode->parent == NULL) {
353 avlcursor->curnode = NULL;
354 return NULL;
355 }
356
357 avlcursor->curnode = avlnode->parent;
358 return avlnode->parent->item;
359}
360
361
362/*
363 * zAVLCloseSearchNode:
364 * Return a pointer to the node closest to the given key.
365 * Returns NULL if the AVL tree is empty.
366 */
367static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
368 int * ok)
369{
370 zAVLNode *node;
371
372 *ok = ZAVL_NO;
373
374 node = avltree->top;
375
376 if (!node)
377 return NULL;
378
379 for (;;) {
380 if (!zAVLKey_cmp(avltree, node->key, key))
381 {
382 *ok = ZAVL_OK;
383 return node;
384 }
385
386 if (zAVLKey_cmp(avltree, node->key, key) < 0) {
387 if (node->right)
388 node = node->right;
389 else
390 return node;
391 }
392
393 else {
394 if (node->left)
395 node = node->left;
396 else
397 return node;
398 }
399 }
400}
401
402
403/*
404 * zAVLRebalanceNode:
405 * Rebalances the AVL tree if one side becomes too heavy. This function
406 * assumes that both subtrees are AVL trees with consistant data. This
407 * function has the additional side effect of recalculating the depth of
408 * the tree at this node. It should be noted that at the return of this
409 * function, if a rebalance takes place, the top of this subtree is no
410 * longer going to be the same node.
411 */
412static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode)
413{
414 long depthdiff;
415 zAVLNode *child;
416 zAVLNode *gchild;
417 zAVLNode *origparent;
418 zAVLNode **superparent;
419
420 origparent = avlnode->parent;
421
422 if (origparent) {
423 if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
424 superparent = &(avlnode->parent->left);
425 else
426 superparent = &(avlnode->parent->right);
427 }
428 else
429 superparent = &(avltree->top);
430
431 depthdiff = R_DEPTH(avlnode) - L_DEPTH(avlnode);
432
433 if (depthdiff <= -2 && avlnode->left) {
434 child = avlnode->left;
435
436 if (L_DEPTH(child) >= R_DEPTH(child)) {
437 avlnode->left = child->right;
438 if (avlnode->left != NULL)
439 avlnode->left->parent = avlnode;
440 avlnode->depth = CALC_DEPTH(avlnode);
441 child->right = avlnode;
442 if (child->right != NULL)
443 child->right->parent = child;
444 child->depth = CALC_DEPTH(child);
445 *superparent = child;
446 child->parent = origparent;
447 }
448
449 else {
450 gchild = child->right;
451 if (gchild)
452 {
453 avlnode->left = gchild->right;
454 if (avlnode->left != NULL)
455 avlnode->left->parent = avlnode;
456 avlnode->depth = CALC_DEPTH(avlnode);
457 child->right = gchild->left;
458 if (child->right != NULL)
459 child->right->parent = child;
460 child->depth = CALC_DEPTH(child);
461 gchild->right = avlnode;
462 if (gchild->right != NULL)
463 gchild->right->parent = gchild;
464 gchild->left = child;
465 if (gchild->left != NULL)
466 gchild->left->parent = gchild;
467 gchild->depth = CALC_DEPTH(gchild);
468 *superparent = gchild;
469 gchild->parent = origparent;
470 }
471 }
472 }
473
474 else if (depthdiff >= 2 && avlnode->right) {
475 child = avlnode->right;
476
477 if (R_DEPTH(child) >= L_DEPTH(child)) {
478 avlnode->right = child->left;
479 if (avlnode->right != NULL)
480 avlnode->right->parent = avlnode;
481 avlnode->depth = CALC_DEPTH(avlnode);
482 child->left = avlnode;
483 if (child->left != NULL)
484 child->left->parent = child;
485 child->depth = CALC_DEPTH(child);
486 *superparent = child;
487 child->parent = origparent;
488 }
489
490 else {
491 gchild = child->left;
492 if (gchild)
493 {
494 avlnode->right = gchild->left;
495 if (avlnode->right != NULL)
496 avlnode->right->parent = avlnode;
497 avlnode->depth = CALC_DEPTH(avlnode);
498 child->left = gchild->right;
499 if (child->left != NULL)
500 child->left->parent = child;
501 child->depth = CALC_DEPTH(child);
502 gchild->left = avlnode;
503 if (gchild->left != NULL)
504 gchild->left->parent = gchild;
505 gchild->right = child;
506 if (gchild->right != NULL)
507 gchild->right->parent = gchild;
508 gchild->depth = CALC_DEPTH(gchild);
509 *superparent = gchild;
510 gchild->parent = origparent;
511 }
512 }
513 }
514
515 else {
516 avlnode->depth = CALC_DEPTH(avlnode);
517 }
518}
519
520
521/*
522 * zAVLFreeBranch:
523 * Free memory used by this node and its item. If the freeitem argument
524 * is not NULL, then that function is called on the items to free their
525 * memory as well. In other words, the freeitem function is a
526 * destructor for the items in the tree.
527 */
528static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item))
529{
530 if (avlnode->left)
531 zAVLFreeBranch(avlnode->left, freeitem);
532 if (avlnode->right)
533 zAVLFreeBranch(avlnode->right, freeitem);
534 if (freeitem)
535 freeitem(avlnode->item);
536 free(avlnode);
537}
538
539
540/*
541 * zAVLFillVacancy:
542 * Given a vacancy in the AVL tree by it's parent, children, and parent
543 * component pointer, fill that vacancy.
544 */
545static void zAVLFillVacancy (zAVLTree *avltree,
546 zAVLNode *origparent, zAVLNode **superparent,
547 zAVLNode *left, zAVLNode *right)
548{
549 zAVLNode *avlnode;
550 zAVLNode *balnode;
551 zAVLNode *nextbalnode;
552
553 if (left == NULL) {
554 if (right)
555 right->parent = origparent;
556
557 *superparent = right;
558 balnode = origparent;
559 }
560
561 else {
562 for (avlnode = left; avlnode->right != NULL; avlnode = avlnode->right);
563
564 if (avlnode == left) {
565 balnode = avlnode;
566 }
567 else {
568 balnode = avlnode->parent;
569 balnode->right = avlnode->left;
570 if (balnode->right != NULL)
571 balnode->right->parent = balnode;
572 avlnode->left = left;
573 left->parent = avlnode;
574 }
575
576 avlnode->right = right;
577 if (right != NULL)
578 right->parent = avlnode;
579 *superparent = avlnode;
580 avlnode->parent = origparent;
581 }
582
583 for (; balnode; balnode = nextbalnode) {
584 nextbalnode = balnode->parent;
585 zAVLRebalanceNode(avltree, balnode);
586 }
587}
Note: See TracBrowser for help on using the repository browser.