1 /* avl.c - routines to implement an avl tree */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005 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.
25 #include <ac/stdlib.h>
28 #define ber_memalloc malloc
29 #define ber_memrealloc realloc
30 #define ber_memfree free
38 static const int avl_bfs[] = {LH, RH};
41 * Threaded AVL trees - for fast in-order traversal of nodes.
44 * tavl_insert -- insert a node containing data data into the avl tree
45 * with root root. fcmp is a function to call to compare the data portion
46 * of two nodes. it should take two arguments and return <, >, or == 0,
47 * depending on whether its first argument is <, >, or == its second
48 * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
49 * node is inserted. it should return 0, or -1 and its return value
50 * will be the return value from avl_insert in the case of a duplicate node.
51 * the function will be called with the original node's data as its first
52 * argument and with the incoming duplicate node's data as its second
53 * argument. this could be used, for example, to keep a count with each
56 * NOTE: this routine may malloc memory
59 tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
61 Avlnode *t, *p, *s, *q, *r;
64 if ( *root == NULL ) {
65 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
68 r->avl_link[0] = r->avl_link[1] = NULL;
71 r->avl_bits[0] = r->avl_bits[1] = AVL_THREAD;
80 /* find insertion point */
82 cmp = fcmp( data, p->avl_data );
84 return (*fdup)( p->avl_data, data );
87 q = avl_child( p, cmp );
90 if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
93 q->avl_link[cmp] = p->avl_link[cmp];
94 q->avl_link[!cmp] = p;
97 q->avl_bits[0] = q->avl_bits[1] = AVL_THREAD;
100 p->avl_bits[cmp] = AVL_CHILD;
102 } else if ( q->avl_bf ) {
109 /* adjust balance factors */
110 cmp = fcmp( data, s->avl_data ) > 0;
111 r = p = s->avl_link[cmp];
115 cmp = fcmp( data, p->avl_data ) > 0;
116 p->avl_bf = avl_bfs[cmp];
117 p = p->avl_link[cmp];
120 /* checks and balances */
122 if ( s->avl_bf == EH ) {
125 } else if ( s->avl_bf == -a ) {
128 } else if ( s->avl_bf == a ) {
131 if ( r->avl_bf == a ) {
132 /* single rotation */
134 if ( r->avl_bits[ncmp] == AVL_THREAD ) {
135 r->avl_bits[ncmp] = AVL_CHILD;
136 s->avl_bits[cmp] = AVL_THREAD;
138 s->avl_link[cmp] = r->avl_link[ncmp];
139 r->avl_link[ncmp] = s;
143 } else if ( r->avl_bf == -a ) {
144 /* double rotation */
145 p = r->avl_link[ncmp];
146 if ( p->avl_bits[cmp] == AVL_THREAD ) {
147 p->avl_bits[cmp] = AVL_CHILD;
148 r->avl_bits[ncmp] = AVL_THREAD;
150 r->avl_link[ncmp] = p->avl_link[cmp];
151 p->avl_link[cmp] = r;
153 if ( p->avl_bits[ncmp] == AVL_THREAD ) {
154 p->avl_bits[ncmp] = AVL_CHILD;
155 s->avl_link[cmp] = p;
156 s->avl_bits[cmp] = AVL_THREAD;
158 s->avl_link[cmp] = p->avl_link[ncmp];
159 p->avl_link[ncmp] = s;
161 if ( p->avl_bf == a ) {
164 } else if ( p->avl_bf == -a ) {
176 else if ( s == t->avl_right )
186 tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
188 Avlnode *p, *q, *r, *s, *top;
189 int side, side_bf, shorter, nside;
192 Avlnode *pptr[sizeof(void *)*8];
193 unsigned char pdir[sizeof(void *)*8];
202 side = fcmp( data, p->avl_data );
209 if ( p->avl_bits[side] == AVL_THREAD )
211 p = p->avl_link[side];
215 /* If this node has two children, swap so we are deleting a node with
218 if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD &&
219 p->avl_link[0] && p->avl_link[1] ) {
221 /* find the immediate predecessor <q> */
225 while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) {
231 p->avl_data = q->avl_data;
235 /* now <p> has at most one child, get it */
236 if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) {
238 /* Preserve thread continuity */
241 } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) {
248 r = p->avl_link[pdir[depth-1]];
260 /* set the child into p's parent */
264 p->avl_link[side] = q;
266 /* Update child thread */
268 for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
269 q = q->avl_link[nside] ) ;
270 q->avl_link[nside] = r;
272 p->avl_bits[side] = AVL_THREAD;
273 p->avl_link[side] = r;
283 side_bf = avl_bfs[side];
285 /* case 1: height unchanged */
286 if ( p->avl_bf == EH ) {
287 /* Tree is now heavier on opposite side */
288 p->avl_bf = avl_bfs[nside];
291 } else if ( p->avl_bf == side_bf ) {
292 /* case 2: taller subtree shortened, height reduced */
295 /* case 3: shorter subtree shortened */
297 top = pptr[depth-1]; /* p->parent; */
300 /* set <q> to the taller of the two subtrees of <p> */
301 q = p->avl_link[nside];
302 if ( q->avl_bf == EH ) {
303 /* case 3a: height unchanged, single rotate */
304 if ( q->avl_bits[side] == AVL_THREAD ) {
305 q->avl_bits[side] = AVL_CHILD;
306 p->avl_bits[nside] = AVL_THREAD;
308 p->avl_link[nside] = q->avl_link[side];
309 q->avl_link[side] = p;
313 p->avl_bf = (- side_bf);
315 } else if ( q->avl_bf == p->avl_bf ) {
316 /* case 3b: height reduced, single rotate */
317 if ( q->avl_bits[side] == AVL_THREAD ) {
318 q->avl_bits[side] = AVL_CHILD;
319 p->avl_bits[nside] = AVL_THREAD;
321 p->avl_link[nside] = q->avl_link[side];
322 q->avl_link[side] = p;
329 /* case 3c: height reduced, balance factors opposite */
330 r = q->avl_link[side];
331 if ( r->avl_bits[nside] == AVL_THREAD ) {
332 r->avl_bits[nside] = AVL_CHILD;
333 q->avl_bits[side] = AVL_THREAD;
335 q->avl_link[side] = r->avl_link[nside];
336 r->avl_link[nside] = q;
339 if ( r->avl_bits[side] == AVL_THREAD ) {
340 r->avl_bits[side] = AVL_CHILD;
341 p->avl_bits[nside] = AVL_THREAD;
342 p->avl_link[nside] = r;
344 p->avl_link[nside] = r->avl_link[side];
345 r->avl_link[side] = p;
348 if ( r->avl_bf == side_bf ) {
349 q->avl_bf = (- side_bf);
351 } else if ( r->avl_bf == (- side_bf)) {
361 /* a rotation has caused <q> (or <r> in case 3c) to become
362 * the root. let <p>'s former parent know this.
366 } else if (top->avl_link[0] == p) {
367 top->avl_link[0] = q;
369 top->avl_link[1] = q;
377 } /* end while(shorter) */
383 * tavl_free -- traverse avltree root, freeing the memory it is using.
384 * the dfree() is called to free the data portion of each node. The
385 * number of items actually freed is returned.
389 tavl_free( Avlnode *root, AVL_FREE dfree )
396 nleft = tavl_free( avl_lchild( root ), dfree );
398 nright = tavl_free( avl_rchild( root ), dfree );
401 (*dfree)( root->avl_data );
404 return( nleft + nright + 1 );
408 * tavl_find -- search avltree root for a node with data data. the function
409 * cmp is used to compare things. it is called with data as its first arg
410 * and the current node data as its second. it should return 0 if they match,
411 * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
415 tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
419 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
421 root = avl_child( root, cmp );
427 tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
431 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
433 root = avl_child( root, cmp );
436 return( root ? root->avl_data : 0 );
439 /* Return the leftmost or rightmost node in the tree */
441 tavl_end( Avlnode *root, int dir )
444 while ( root->avl_bits[dir] == AVL_CHILD )
445 root = root->avl_link[dir];
450 /* Return the next node in the given direction */
452 tavl_next( Avlnode *root, int dir )
455 int c = root->avl_bits[dir];
457 root = root->avl_link[dir];
458 if ( c == AVL_CHILD ) {
460 while ( root->avl_bits[dir] == AVL_CHILD )
461 root = root->avl_link[dir];