1
/* avl.c - routines to implement an avl tree */
2
/* $OpenLDAP: pkg/ldap/libraries/liblutil/avl.c,v 1.9.2.3 2008/02/11 23:26:42 kurt Exp $ */
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5
* Copyright 1998-2008 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
38
#include <ac/stdlib.h>
41
#define ber_memalloc malloc
42
#define ber_memrealloc realloc
43
#define ber_memfree free
51
static const int avl_bfs[] = {LH, RH};
54
* avl_insert -- insert a node containing data data into the avl tree
55
* with root root. fcmp is a function to call to compare the data portion
56
* of two nodes. it should take two arguments and return <, >, or == 0,
57
* depending on whether its first argument is <, >, or == its second
58
* argument (like strcmp, e.g.). fdup is a function to call when a duplicate
59
* node is inserted. it should return 0, or -1 and its return value
60
* will be the return value from avl_insert in the case of a duplicate node.
61
* the function will be called with the original node's data as its first
62
* argument and with the incoming duplicate node's data as its second
63
* argument. this could be used, for example, to keep a count with each
66
* NOTE: this routine may malloc memory
69
avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
71
Avlnode *t, *p, *s, *q, *r;
74
if ( *root == NULL ) {
75
if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
78
r->avl_link[0] = r->avl_link[1] = NULL;
89
/* find insertion point */
91
cmp = fcmp( data, p->avl_data );
93
return (*fdup)( p->avl_data, data );
99
if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
102
q->avl_link[0] = q->avl_link[1] = NULL;
106
p->avl_link[cmp] = q;
108
} else if ( q->avl_bf ) {
115
/* adjust balance factors */
116
cmp = fcmp( data, s->avl_data ) > 0;
117
r = p = s->avl_link[cmp];
121
cmp = fcmp( data, p->avl_data ) > 0;
122
p->avl_bf = avl_bfs[cmp];
123
p = p->avl_link[cmp];
126
/* checks and balances */
128
if ( s->avl_bf == EH ) {
131
} else if ( s->avl_bf == -a ) {
134
} else if ( s->avl_bf == a ) {
137
if ( r->avl_bf == a ) {
138
/* single rotation */
140
s->avl_link[cmp] = r->avl_link[ncmp];
141
r->avl_link[ncmp] = s;
144
} else if ( r->avl_bf == -a ) {
145
/* double rotation */
146
p = r->avl_link[ncmp];
147
r->avl_link[ncmp] = p->avl_link[cmp];
148
p->avl_link[cmp] = r;
149
s->avl_link[cmp] = p->avl_link[ncmp];
150
p->avl_link[ncmp] = s;
152
if ( p->avl_bf == a ) {
155
} else if ( p->avl_bf == -a ) {
167
else if ( s == t->avl_right )
177
avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
179
Avlnode *p, *q, *r, *top;
180
int side, side_bf, shorter, nside;
183
Avlnode *pptr[sizeof(void *)*8];
184
unsigned char pdir[sizeof(void *)*8];
193
side = fcmp( data, p->avl_data );
200
p = p->avl_link[side];
206
/* If this node has two children, swap so we are deleting a node with
209
if ( p->avl_link[0] && p->avl_link[1] ) {
211
/* find the immediate predecessor <q> */
215
while (q->avl_link[1]) {
222
p->avl_link[0] = q->avl_link[0];
225
q->avl_link[1] = p->avl_link[1];
226
p->avl_link[1] = NULL;
228
q->avl_bf = p->avl_bf;
230
/* fix stack positions: old parent of p points to q */
234
r->avl_link[pdir[side-1]] = q;
238
/* new parent of p points to p */
239
if ( depth-side > 1 ) {
247
/* now <p> has at most one child, get it */
248
q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
257
/* set the child into p's parent */
261
p->avl_link[side] = q;
270
side_bf = avl_bfs[side];
272
/* case 1: height unchanged */
273
if ( p->avl_bf == EH ) {
274
/* Tree is now heavier on opposite side */
275
p->avl_bf = avl_bfs[nside];
278
} else if ( p->avl_bf == side_bf ) {
279
/* case 2: taller subtree shortened, height reduced */
282
/* case 3: shorter subtree shortened */
284
top = pptr[depth-1]; /* p->parent; */
287
/* set <q> to the taller of the two subtrees of <p> */
288
q = p->avl_link[nside];
289
if ( q->avl_bf == EH ) {
290
/* case 3a: height unchanged, single rotate */
291
p->avl_link[nside] = q->avl_link[side];
292
q->avl_link[side] = p;
295
p->avl_bf = (- side_bf);
297
} else if ( q->avl_bf == p->avl_bf ) {
298
/* case 3b: height reduced, single rotate */
299
p->avl_link[nside] = q->avl_link[side];
300
q->avl_link[side] = p;
306
/* case 3c: height reduced, balance factors opposite */
307
r = q->avl_link[side];
308
q->avl_link[side] = r->avl_link[nside];
309
r->avl_link[nside] = q;
311
p->avl_link[nside] = r->avl_link[side];
312
r->avl_link[side] = p;
314
if ( r->avl_bf == side_bf ) {
315
q->avl_bf = (- side_bf);
317
} else if ( r->avl_bf == (- side_bf)) {
327
/* a rotation has caused <q> (or <r> in case 3c) to become
328
* the root. let <p>'s former parent know this.
332
} else if (top->avl_link[0] == p) {
333
top->avl_link[0] = q;
335
top->avl_link[1] = q;
343
} /* end while(shorter) */
349
avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
352
return( AVL_NOMORE );
354
if ( root->avl_left != 0 )
355
if ( avl_inapply( root->avl_left, fn, arg, stopflag )
359
if ( (*fn)( root->avl_data, arg ) == stopflag )
362
if ( root->avl_right == 0 )
363
return( AVL_NOMORE );
365
return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
369
avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
372
return( AVL_NOMORE );
374
if ( root->avl_left != 0 )
375
if ( avl_postapply( root->avl_left, fn, arg, stopflag )
379
if ( root->avl_right != 0 )
380
if ( avl_postapply( root->avl_right, fn, arg, stopflag )
384
return( (*fn)( root->avl_data, arg ) );
388
avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
391
return( AVL_NOMORE );
393
if ( (*fn)( root->avl_data, arg ) == stopflag )
396
if ( root->avl_left != 0 )
397
if ( avl_preapply( root->avl_left, fn, arg, stopflag )
401
if ( root->avl_right == 0 )
402
return( AVL_NOMORE );
404
return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
408
* avl_apply -- avl tree root is traversed, function fn is called with
409
* arguments arg and the data portion of each node. if fn returns stopflag,
410
* the traversal is cut short, otherwise it continues. Do not use -6 as
411
* a stopflag, as this is what is used to indicate the traversal ran out
416
avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
420
return( avl_inapply( root, fn, arg, stopflag ) );
422
return( avl_preapply( root, fn, arg, stopflag ) );
424
return( avl_postapply( root, fn, arg, stopflag ) );
426
fprintf( stderr, "Invalid traversal type %d\n", type );
434
* avl_prefixapply - traverse avl tree root, applying function fprefix
435
* to any nodes that match. fcmp is called with data as its first arg
436
* and the current node's data as its second arg. it should return
437
* 0 if they match, < 0 if data is less, and > 0 if data is greater.
438
* the idea is to efficiently find all nodes that are prefixes of
439
* some key... Like avl_apply, this routine also takes a stopflag
440
* and will return prematurely if fmatch returns this value. Otherwise,
441
* AVL_NOMORE is returned.
458
return( AVL_NOMORE );
460
cmp = (*fcmp)( data, root->avl_data /* , carg */);
462
if ( (*fmatch)( root->avl_data, marg ) == stopflag )
465
if ( root->avl_left != 0 )
466
if ( avl_prefixapply( root->avl_left, data, fmatch,
467
marg, fcmp, carg, stopflag ) == stopflag )
470
if ( root->avl_right != 0 )
471
return( avl_prefixapply( root->avl_right, data, fmatch,
472
marg, fcmp, carg, stopflag ) );
474
return( AVL_NOMORE );
476
} else if ( cmp < 0 ) {
477
if ( root->avl_left != 0 )
478
return( avl_prefixapply( root->avl_left, data, fmatch,
479
marg, fcmp, carg, stopflag ) );
481
if ( root->avl_right != 0 )
482
return( avl_prefixapply( root->avl_right, data, fmatch,
483
marg, fcmp, carg, stopflag ) );
486
return( AVL_NOMORE );
490
* avl_free -- traverse avltree root, freeing the memory it is using.
491
* the dfree() is called to free the data portion of each node. The
492
* number of items actually freed is returned.
496
avl_free( Avlnode *root, AVL_FREE dfree )
504
if ( root->avl_left != 0 )
505
nleft = avl_free( root->avl_left, dfree );
507
if ( root->avl_right != 0 )
508
nright = avl_free( root->avl_right, dfree );
511
(*dfree)( root->avl_data );
514
return( nleft + nright + 1 );
518
* avl_find -- search avltree root for a node with data data. the function
519
* cmp is used to compare things. it is called with data as its first arg
520
* and the current node data as its second. it should return 0 if they match,
521
* < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
525
avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
529
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
531
root = root->avl_link[cmp];
537
avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
541
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
543
root = root->avl_link[cmp];
546
return( root ? root->avl_data : 0 );
550
* avl_find_lin -- search avltree root linearly for a node with data data.
551
* the function cmp is used to compare things. it is called with data as its
552
* first arg and the current node data as its second. it should return 0 if
553
* they match, non-zero otherwise.
557
avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
564
if ( (*fcmp)( data, root->avl_data ) == 0 )
565
return( root->avl_data );
567
if ( root->avl_left != 0 )
568
if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
572
if ( root->avl_right == 0 )
575
return( avl_find_lin( root->avl_right, data, fcmp ) );
578
/* NON-REENTRANT INTERFACE */
580
static void* *avl_list;
581
static int avl_maxlist;
582
static int avl_nextlist;
584
#define AVL_GRABSIZE 100
588
avl_buildlist( void* data, void* arg )
592
if ( avl_list == (void* *) 0 ) {
593
avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
594
slots = AVL_GRABSIZE;
596
} else if ( avl_maxlist == slots ) {
597
slots += AVL_GRABSIZE;
598
avl_list = (void* *) ber_memrealloc( (char *) avl_list,
599
(unsigned) slots * sizeof(void*));
602
avl_list[ avl_maxlist++ ] = data;
608
* avl_getfirst() and avl_getnext() are provided as alternate tree
609
* traversal methods, to be used when a single function cannot be
610
* provided to be called with every node in the tree. avl_getfirst()
611
* traverses the tree and builds a linear list of all the nodes,
612
* returning the first node. avl_getnext() returns the next thing
613
* on the list built by avl_getfirst(). This means that avl_getfirst()
614
* can take a while, and that the tree should not be messed with while
615
* being traversed in this way, and that multiple traversals (even of
616
* different trees) cannot be active at once.
620
avl_getfirst( Avlnode *root )
623
ber_memfree( (char *) avl_list);
624
avl_list = (void* *) 0;
632
(void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
634
return( avl_list[ avl_nextlist++ ] );
643
if ( avl_nextlist == avl_maxlist ) {
644
ber_memfree( (void*) avl_list);
645
avl_list = (void* *) 0;
649
return( avl_list[ avl_nextlist++ ] );
652
/* end non-reentrant code */
656
avl_dup_error( void* left, void* right )
662
avl_dup_ok( void* left, void* right )