1 /* avl.c - routines to implement an avl tree */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2010 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1993 Regents of the University of Michigan.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP). Additional significant contributors
31 * Hallvard B. Furuseth
39 #include <ac/stdlib.h>
42 #define ber_memalloc malloc
43 #define ber_memrealloc realloc
44 #define ber_memfree free
52 /* Maximum tree depth this host's address space could support */
53 #define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
55 static const int avl_bfs[] = {LH, RH};
58 * avl_insert -- insert a node containing data data into the avl tree
59 * with root root. fcmp is a function to call to compare the data portion
60 * of two nodes. it should take two arguments and return <, >, or == 0,
61 * depending on whether its first argument is <, >, or == its second
62 * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
63 * node is inserted. it should return 0, or -1 and its return value
64 * will be the return value from avl_insert in the case of a duplicate node.
65 * the function will be called with the original node's data as its first
66 * argument and with the incoming duplicate node's data as its second
67 * argument. this could be used, for example, to keep a count with each
70 * NOTE: this routine may malloc memory
73 avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
75 Avlnode *t, *p, *s, *q, *r;
78 if ( *root == NULL ) {
79 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
82 r->avl_link[0] = r->avl_link[1] = NULL;
93 /* find insertion point */
95 cmp = fcmp( data, p->avl_data );
97 return (*fdup)( p->avl_data, data );
100 q = p->avl_link[cmp];
103 if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
106 q->avl_link[0] = q->avl_link[1] = NULL;
110 p->avl_link[cmp] = q;
112 } else if ( q->avl_bf ) {
119 /* adjust balance factors */
120 cmp = fcmp( data, s->avl_data ) > 0;
121 r = p = s->avl_link[cmp];
125 cmp = fcmp( data, p->avl_data ) > 0;
126 p->avl_bf = avl_bfs[cmp];
127 p = p->avl_link[cmp];
130 /* checks and balances */
132 if ( s->avl_bf == EH ) {
135 } else if ( s->avl_bf == -a ) {
138 } else if ( s->avl_bf == a ) {
141 if ( r->avl_bf == a ) {
142 /* single rotation */
144 s->avl_link[cmp] = r->avl_link[ncmp];
145 r->avl_link[ncmp] = s;
148 } else if ( r->avl_bf == -a ) {
149 /* double rotation */
150 p = r->avl_link[ncmp];
151 r->avl_link[ncmp] = p->avl_link[cmp];
152 p->avl_link[cmp] = r;
153 s->avl_link[cmp] = p->avl_link[ncmp];
154 p->avl_link[ncmp] = s;
156 if ( p->avl_bf == a ) {
159 } else if ( p->avl_bf == -a ) {
171 else if ( s == t->avl_right )
181 avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
183 Avlnode *p, *q, *r, *top;
184 int side, side_bf, shorter, nside;
187 Avlnode *pptr[MAX_TREE_DEPTH];
188 unsigned char pdir[MAX_TREE_DEPTH];
197 side = fcmp( data, p->avl_data );
204 p = p->avl_link[side];
210 /* If this node has two children, swap so we are deleting a node with
213 if ( p->avl_link[0] && p->avl_link[1] ) {
215 /* find the immediate predecessor <q> */
219 while (q->avl_link[1]) {
226 p->avl_link[0] = q->avl_link[0];
229 q->avl_link[1] = p->avl_link[1];
230 p->avl_link[1] = NULL;
232 q->avl_bf = p->avl_bf;
234 /* fix stack positions: old parent of p points to q */
238 r->avl_link[pdir[side-1]] = q;
242 /* new parent of p points to p */
243 if ( depth-side > 1 ) {
251 /* now <p> has at most one child, get it */
252 q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
261 /* set the child into p's parent */
265 p->avl_link[side] = q;
274 side_bf = avl_bfs[side];
276 /* case 1: height unchanged */
277 if ( p->avl_bf == EH ) {
278 /* Tree is now heavier on opposite side */
279 p->avl_bf = avl_bfs[nside];
282 } else if ( p->avl_bf == side_bf ) {
283 /* case 2: taller subtree shortened, height reduced */
286 /* case 3: shorter subtree shortened */
288 top = pptr[depth-1]; /* p->parent; */
291 /* set <q> to the taller of the two subtrees of <p> */
292 q = p->avl_link[nside];
293 if ( q->avl_bf == EH ) {
294 /* case 3a: height unchanged, single rotate */
295 p->avl_link[nside] = q->avl_link[side];
296 q->avl_link[side] = p;
299 p->avl_bf = (- side_bf);
301 } else if ( q->avl_bf == p->avl_bf ) {
302 /* case 3b: height reduced, single rotate */
303 p->avl_link[nside] = q->avl_link[side];
304 q->avl_link[side] = p;
310 /* case 3c: height reduced, balance factors opposite */
311 r = q->avl_link[side];
312 q->avl_link[side] = r->avl_link[nside];
313 r->avl_link[nside] = q;
315 p->avl_link[nside] = r->avl_link[side];
316 r->avl_link[side] = p;
318 if ( r->avl_bf == side_bf ) {
319 q->avl_bf = (- side_bf);
321 } else if ( r->avl_bf == (- side_bf)) {
331 /* a rotation has caused <q> (or <r> in case 3c) to become
332 * the root. let <p>'s former parent know this.
336 } else if (top->avl_link[0] == p) {
337 top->avl_link[0] = q;
339 top->avl_link[1] = q;
347 } /* end while(shorter) */
353 avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
356 return( AVL_NOMORE );
358 if ( root->avl_left != 0 )
359 if ( avl_inapply( root->avl_left, fn, arg, stopflag )
363 if ( (*fn)( root->avl_data, arg ) == stopflag )
366 if ( root->avl_right == 0 )
367 return( AVL_NOMORE );
369 return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
373 avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
376 return( AVL_NOMORE );
378 if ( root->avl_left != 0 )
379 if ( avl_postapply( root->avl_left, fn, arg, stopflag )
383 if ( root->avl_right != 0 )
384 if ( avl_postapply( root->avl_right, fn, arg, stopflag )
388 return( (*fn)( root->avl_data, arg ) );
392 avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
395 return( AVL_NOMORE );
397 if ( (*fn)( root->avl_data, arg ) == stopflag )
400 if ( root->avl_left != 0 )
401 if ( avl_preapply( root->avl_left, fn, arg, stopflag )
405 if ( root->avl_right == 0 )
406 return( AVL_NOMORE );
408 return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
412 * avl_apply -- avl tree root is traversed, function fn is called with
413 * arguments arg and the data portion of each node. if fn returns stopflag,
414 * the traversal is cut short, otherwise it continues. Do not use -6 as
415 * a stopflag, as this is what is used to indicate the traversal ran out
420 avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
424 return( avl_inapply( root, fn, arg, stopflag ) );
426 return( avl_preapply( root, fn, arg, stopflag ) );
428 return( avl_postapply( root, fn, arg, stopflag ) );
430 fprintf( stderr, "Invalid traversal type %d\n", type );
438 * avl_prefixapply - traverse avl tree root, applying function fprefix
439 * to any nodes that match. fcmp is called with data as its first arg
440 * and the current node's data as its second arg. it should return
441 * 0 if they match, < 0 if data is less, and > 0 if data is greater.
442 * the idea is to efficiently find all nodes that are prefixes of
443 * some key... Like avl_apply, this routine also takes a stopflag
444 * and will return prematurely if fmatch returns this value. Otherwise,
445 * AVL_NOMORE is returned.
462 return( AVL_NOMORE );
464 cmp = (*fcmp)( data, root->avl_data /* , carg */);
466 if ( (*fmatch)( root->avl_data, marg ) == stopflag )
469 if ( root->avl_left != 0 )
470 if ( avl_prefixapply( root->avl_left, data, fmatch,
471 marg, fcmp, carg, stopflag ) == stopflag )
474 if ( root->avl_right != 0 )
475 return( avl_prefixapply( root->avl_right, data, fmatch,
476 marg, fcmp, carg, stopflag ) );
478 return( AVL_NOMORE );
480 } else if ( cmp < 0 ) {
481 if ( root->avl_left != 0 )
482 return( avl_prefixapply( root->avl_left, data, fmatch,
483 marg, fcmp, carg, stopflag ) );
485 if ( root->avl_right != 0 )
486 return( avl_prefixapply( root->avl_right, data, fmatch,
487 marg, fcmp, carg, stopflag ) );
490 return( AVL_NOMORE );
494 * avl_free -- traverse avltree root, freeing the memory it is using.
495 * the dfree() is called to free the data portion of each node. The
496 * number of items actually freed is returned.
500 avl_free( Avlnode *root, AVL_FREE dfree )
508 if ( root->avl_left != 0 )
509 nleft = avl_free( root->avl_left, dfree );
511 if ( root->avl_right != 0 )
512 nright = avl_free( root->avl_right, dfree );
515 (*dfree)( root->avl_data );
518 return( nleft + nright + 1 );
522 * avl_find -- search avltree root for a node with data data. the function
523 * cmp is used to compare things. it is called with data as its first arg
524 * and the current node data as its second. it should return 0 if they match,
525 * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
529 avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
533 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
535 root = root->avl_link[cmp];
541 avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
545 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
547 root = root->avl_link[cmp];
550 return( root ? root->avl_data : 0 );
554 * avl_find_lin -- search avltree root linearly for a node with data data.
555 * the function cmp is used to compare things. it is called with data as its
556 * first arg and the current node data as its second. it should return 0 if
557 * they match, non-zero otherwise.
561 avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
568 if ( (*fcmp)( data, root->avl_data ) == 0 )
569 return( root->avl_data );
571 if ( root->avl_left != 0 )
572 if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
576 if ( root->avl_right == 0 )
579 return( avl_find_lin( root->avl_right, data, fcmp ) );
582 /* NON-REENTRANT INTERFACE */
584 static void* *avl_list;
585 static int avl_maxlist;
586 static int avl_nextlist;
588 #define AVL_GRABSIZE 100
592 avl_buildlist( void* data, void* arg )
596 if ( avl_list == (void* *) 0 ) {
597 avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
598 slots = AVL_GRABSIZE;
600 } else if ( avl_maxlist == slots ) {
601 slots += AVL_GRABSIZE;
602 avl_list = (void* *) ber_memrealloc( (char *) avl_list,
603 (unsigned) slots * sizeof(void*));
606 avl_list[ avl_maxlist++ ] = data;
612 * avl_getfirst() and avl_getnext() are provided as alternate tree
613 * traversal methods, to be used when a single function cannot be
614 * provided to be called with every node in the tree. avl_getfirst()
615 * traverses the tree and builds a linear list of all the nodes,
616 * returning the first node. avl_getnext() returns the next thing
617 * on the list built by avl_getfirst(). This means that avl_getfirst()
618 * can take a while, and that the tree should not be messed with while
619 * being traversed in this way, and that multiple traversals (even of
620 * different trees) cannot be active at once.
624 avl_getfirst( Avlnode *root )
627 ber_memfree( (char *) avl_list);
628 avl_list = (void* *) 0;
636 (void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
638 return( avl_list[ avl_nextlist++ ] );
647 if ( avl_nextlist == avl_maxlist ) {
648 ber_memfree( (void*) avl_list);
649 avl_list = (void* *) 0;
653 return( avl_list[ avl_nextlist++ ] );
656 /* end non-reentrant code */
660 avl_dup_error( void* left, void* right )
666 avl_dup_ok( void* left, void* right )