1 /* avl.c - routines to implement an avl tree */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2016 The OpenLDAP Foundation.
6 * Portions Copyright (c) 2005 by Howard Chu, Symas Corp.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Howard Chu for inclusion
19 * in OpenLDAP software.
26 #include <ac/stdlib.h>
29 #define ber_memalloc malloc
30 #define ber_memrealloc realloc
31 #define ber_memfree free
39 /* Maximum tree depth this host's address space could support */
40 #define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
42 static const int avl_bfs[] = {LH, RH};
45 * Threaded AVL trees - for fast in-order traversal of nodes.
48 * tavl_insert -- insert a node containing data data into the avl tree
49 * with root root. fcmp is a function to call to compare the data portion
50 * of two nodes. it should take two arguments and return <, >, or == 0,
51 * depending on whether its first argument is <, >, or == its second
52 * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
53 * node is inserted. it should return 0, or -1 and its return value
54 * will be the return value from avl_insert in the case of a duplicate node.
55 * the function will be called with the original node's data as its first
56 * argument and with the incoming duplicate node's data as its second
57 * argument. this could be used, for example, to keep a count with each
60 * NOTE: this routine may malloc memory
63 tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
65 Avlnode *t, *p, *s, *q, *r;
68 if ( *root == NULL ) {
69 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
72 r->avl_link[0] = r->avl_link[1] = NULL;
75 r->avl_bits[0] = r->avl_bits[1] = AVL_THREAD;
84 /* find insertion point */
86 cmp = fcmp( data, p->avl_data );
88 return (*fdup)( p->avl_data, data );
91 q = avl_child( p, cmp );
94 if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
97 q->avl_link[cmp] = p->avl_link[cmp];
98 q->avl_link[!cmp] = p;
101 q->avl_bits[0] = q->avl_bits[1] = AVL_THREAD;
103 p->avl_link[cmp] = q;
104 p->avl_bits[cmp] = AVL_CHILD;
106 } else if ( q->avl_bf ) {
113 /* adjust balance factors */
114 cmp = fcmp( data, s->avl_data ) > 0;
115 r = p = s->avl_link[cmp];
119 cmp = fcmp( data, p->avl_data ) > 0;
120 p->avl_bf = avl_bfs[cmp];
121 p = p->avl_link[cmp];
124 /* checks and balances */
126 if ( s->avl_bf == EH ) {
129 } else if ( s->avl_bf == -a ) {
132 } else if ( s->avl_bf == a ) {
135 if ( r->avl_bf == a ) {
136 /* single rotation */
138 if ( r->avl_bits[ncmp] == AVL_THREAD ) {
139 r->avl_bits[ncmp] = AVL_CHILD;
140 s->avl_bits[cmp] = AVL_THREAD;
142 s->avl_link[cmp] = r->avl_link[ncmp];
143 r->avl_link[ncmp] = s;
147 } else if ( r->avl_bf == -a ) {
148 /* double rotation */
149 p = r->avl_link[ncmp];
150 if ( p->avl_bits[cmp] == AVL_THREAD ) {
151 p->avl_bits[cmp] = AVL_CHILD;
152 r->avl_bits[ncmp] = AVL_THREAD;
154 r->avl_link[ncmp] = p->avl_link[cmp];
155 p->avl_link[cmp] = r;
157 if ( p->avl_bits[ncmp] == AVL_THREAD ) {
158 p->avl_bits[ncmp] = AVL_CHILD;
159 s->avl_link[cmp] = p;
160 s->avl_bits[cmp] = AVL_THREAD;
162 s->avl_link[cmp] = p->avl_link[ncmp];
163 p->avl_link[ncmp] = s;
165 if ( p->avl_bf == a ) {
168 } else if ( p->avl_bf == -a ) {
180 else if ( s == t->avl_right )
190 tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
192 Avlnode *p, *q, *r, *top;
193 int side, side_bf, shorter, nside = -1;
196 Avlnode *pptr[MAX_TREE_DEPTH];
197 unsigned char pdir[MAX_TREE_DEPTH];
206 side = fcmp( data, p->avl_data );
213 if ( p->avl_bits[side] == AVL_THREAD )
215 p = p->avl_link[side];
219 /* If this node has two children, swap so we are deleting a node with
222 if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD &&
223 p->avl_link[0] && p->avl_link[1] ) {
225 /* find the immediate predecessor <q> */
229 while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) {
236 p->avl_link[0] = q->avl_link[0];
239 q->avl_link[1] = p->avl_link[1];
242 p->avl_bits[0] = q->avl_bits[0];
243 p->avl_bits[1] = q->avl_bits[1];
244 q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD;
246 q->avl_bf = p->avl_bf;
248 /* fix stack positions: old parent of p points to q */
252 r->avl_link[pdir[side-1]] = q;
256 /* new parent of p points to p */
257 if ( depth-side > 1 ) {
264 /* fix right subtree: successor of p points to q */
266 while ( r->avl_bits[0] == AVL_CHILD && r->avl_link[0] )
271 /* now <p> has at most one child, get it */
272 if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) {
274 /* Preserve thread continuity */
277 } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) {
284 r = p->avl_link[pdir[depth-1]];
291 /* Update child thread */
293 for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
294 q = q->avl_link[nside] ) ;
295 q->avl_link[nside] = r;
303 /* set the child into p's parent */
307 p->avl_link[side] = q;
310 p->avl_bits[side] = AVL_THREAD;
311 p->avl_link[side] = r;
321 side_bf = avl_bfs[side];
323 /* case 1: height unchanged */
324 if ( p->avl_bf == EH ) {
325 /* Tree is now heavier on opposite side */
326 p->avl_bf = avl_bfs[nside];
329 } else if ( p->avl_bf == side_bf ) {
330 /* case 2: taller subtree shortened, height reduced */
333 /* case 3: shorter subtree shortened */
335 top = pptr[depth-1]; /* p->parent; */
338 /* set <q> to the taller of the two subtrees of <p> */
339 q = p->avl_link[nside];
340 if ( q->avl_bf == EH ) {
341 /* case 3a: height unchanged, single rotate */
342 if ( q->avl_bits[side] == AVL_THREAD ) {
343 q->avl_bits[side] = AVL_CHILD;
344 p->avl_bits[nside] = AVL_THREAD;
346 p->avl_link[nside] = q->avl_link[side];
347 q->avl_link[side] = p;
351 p->avl_bf = (- side_bf);
353 } else if ( q->avl_bf == p->avl_bf ) {
354 /* case 3b: height reduced, single rotate */
355 if ( q->avl_bits[side] == AVL_THREAD ) {
356 q->avl_bits[side] = AVL_CHILD;
357 p->avl_bits[nside] = AVL_THREAD;
359 p->avl_link[nside] = q->avl_link[side];
360 q->avl_link[side] = p;
367 /* case 3c: height reduced, balance factors opposite */
368 r = q->avl_link[side];
369 if ( r->avl_bits[nside] == AVL_THREAD ) {
370 r->avl_bits[nside] = AVL_CHILD;
371 q->avl_bits[side] = AVL_THREAD;
373 q->avl_link[side] = r->avl_link[nside];
374 r->avl_link[nside] = q;
377 if ( r->avl_bits[side] == AVL_THREAD ) {
378 r->avl_bits[side] = AVL_CHILD;
379 p->avl_bits[nside] = AVL_THREAD;
380 p->avl_link[nside] = r;
382 p->avl_link[nside] = r->avl_link[side];
383 r->avl_link[side] = p;
386 if ( r->avl_bf == side_bf ) {
387 q->avl_bf = (- side_bf);
389 } else if ( r->avl_bf == (- side_bf)) {
399 /* a rotation has caused <q> (or <r> in case 3c) to become
400 * the root. let <p>'s former parent know this.
404 } else if (top->avl_link[0] == p) {
405 top->avl_link[0] = q;
407 top->avl_link[1] = q;
415 } /* end while(shorter) */
421 * tavl_free -- traverse avltree root, freeing the memory it is using.
422 * the dfree() is called to free the data portion of each node. The
423 * number of items actually freed is returned.
427 tavl_free( Avlnode *root, AVL_FREE dfree )
434 nleft = tavl_free( avl_lchild( root ), dfree );
436 nright = tavl_free( avl_rchild( root ), dfree );
439 (*dfree)( root->avl_data );
442 return( nleft + nright + 1 );
446 * tavl_find -- search avltree root for a node with data data. the function
447 * cmp is used to compare things. it is called with data as its first arg
448 * and the current node data as its second. it should return 0 if they match,
449 * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
453 * tavl_find2 - returns Avlnode instead of data pointer.
454 * tavl_find3 - as above, but returns Avlnode even if no match is found.
455 * also set *ret = last comparison result, or -1 if root == NULL.
458 tavl_find3( Avlnode *root, const void *data, AVL_CMP fcmp, int *ret )
461 Avlnode *prev = root;
463 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
466 root = avl_child( root, dir );
469 return root ? root : prev;
473 tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
477 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
479 root = avl_child( root, cmp );
485 tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
489 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
491 root = avl_child( root, cmp );
494 return( root ? root->avl_data : 0 );
497 /* Return the leftmost or rightmost node in the tree */
499 tavl_end( Avlnode *root, int dir )
502 while ( root->avl_bits[dir] == AVL_CHILD )
503 root = root->avl_link[dir];
508 /* Return the next node in the given direction */
510 tavl_next( Avlnode *root, int dir )
513 int c = root->avl_bits[dir];
515 root = root->avl_link[dir];
516 if ( c == AVL_CHILD ) {
518 while ( root->avl_bits[dir] == AVL_CHILD )
519 root = root->avl_link[dir];