source: trunk/src/zAVLTree.c@ 470

Last change on this file since 470 was 465, checked in by katerina, 10 years ago

Fix for ticket #364 (gcc 4.9 compiler bugs).

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