]> git.sur5r.net Git - openldap/blob - libraries/liblutil/avl.c
Replace avl_insert/delete with iterative version
[openldap] / libraries / liblutil / avl.c
1 /* avl.c - routines to implement an avl tree */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16 /* Portions Copyright (c) 1993 Regents of the University of Michigan.
17  * All rights reserved.
18  *
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.
25  */
26 /* ACKNOWLEDGEMENTS:
27  * This work was originally developed by the University of Michigan
28  * (as part of U-MICH LDAP).  Additional significant contributors
29  * include:
30  *   Howard Y. Chu
31  *   Hallvard B. Furuseth
32  *   Kurt D. Zeilenga
33  */
34
35 #include "portable.h"
36
37 #include <stdio.h>
38 #include <ac/stdlib.h>
39
40 #ifdef CSRIMALLOC
41 #define ber_memalloc malloc
42 #define ber_memrealloc realloc
43 #define ber_memfree free
44 #else
45 #include "lber.h"
46 #endif
47
48 #define AVL_INTERNAL
49 #include "avl.h"
50
51 static const int avl_bfs[] = {LH, RH};
52
53 /*
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
64  * node.
65  *
66  * NOTE: this routine may malloc memory
67  */
68 int
69 avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
70 {
71     Avlnode *t, *p, *s, *q, *r;
72     int a, cmp, ncmp;
73
74         if ( *root == NULL ) {
75                 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
76                         return( -1 );
77                 }
78                 r->avl_link[0] = r->avl_link[1] = NULL;
79                 r->avl_data = data;
80                 r->avl_bf = EH;
81                 *root = r;
82
83                 return( 0 );
84         }
85
86     t = NULL;
87     s = p = *root;
88
89         /* find insertion point */
90     while (1) {
91                 cmp = fcmp( data, p->avl_data );
92                 if ( cmp == 0 )
93                         return (*fdup)( p->avl_data, data );
94
95                 cmp = (cmp > 0);
96                 q = p->avl_link[cmp];
97                 if (q == NULL) {
98                         /* insert */
99                         if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
100                                 return( -1 );
101                         }
102                         q->avl_link[0] = q->avl_link[1] = NULL;
103                         q->avl_data = data;
104                         q->avl_bf = EH;
105
106                         p->avl_link[cmp] = q;
107                         break;
108                 } else if ( q->avl_bf ) {
109                         t = p;
110                         s = q;
111                 }
112                 p = q;
113     }
114
115     /* adjust balance factors */
116     cmp = fcmp( data, s->avl_data ) > 0;
117         r = p = s->avl_link[cmp];
118         a = avl_bfs[cmp];
119
120         while ( p != q ) {
121                 cmp = fcmp( data, p->avl_data ) > 0;
122                 p->avl_bf = avl_bfs[cmp];
123                 p = p->avl_link[cmp];
124         }
125
126         /* checks and balances */
127
128         if ( s->avl_bf == EH ) {
129                 s->avl_bf = a;
130                 return 0;
131         } else if ( s->avl_bf == -a ) {
132                 s->avl_bf = EH;
133                 return 0;
134     } else if ( s->avl_bf == a ) {
135                 cmp = (a > 0);
136                 ncmp = !cmp;
137                 if ( r->avl_bf == a ) {
138                         /* single rotation */
139                         p = r;
140                         s->avl_link[cmp] = r->avl_link[ncmp];
141                         r->avl_link[ncmp] = s;
142                         s->avl_bf = 0;
143                         r->avl_bf = 0;
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;
151
152                         if ( p->avl_bf == a ) {
153                                 s->avl_bf = -a;
154                                 r->avl_bf = 0;
155                         } else if ( p->avl_bf == -a ) {
156                                 s->avl_bf = 0;
157                                 r->avl_bf = a;
158                         } else {
159                                 s->avl_bf = 0;
160                                 r->avl_bf = 0;
161                         }
162                         p->avl_bf = 0;
163                 }
164                 /* Update parent */
165                 if ( t == NULL )
166                         *root = p;
167                 else if ( s == t->avl_right )
168                         t->avl_right = p;
169                 else
170                         t->avl_left = p;
171     }
172
173   return 0;
174 }
175
176 void*
177 avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
178 {
179         Avlnode *p, *q, *r, *top;
180         int side, side_bf, shorter, nside;
181
182         /* parent stack */
183         Avlnode *pptr[sizeof(void *)*8];
184         unsigned char pdir[sizeof(void *)*8];
185         int depth = 0;
186
187         if ( *root == NULL )
188                 return NULL;
189
190         p = *root;
191
192         while (1) {
193                 side = fcmp( data, p->avl_data );
194                 if ( !side )
195                         break;
196                 side = ( side > 0 );
197                 pdir[depth] = side;
198                 pptr[depth++] = p;
199
200                 p = p->avl_link[side];
201                 if ( p == NULL )
202                         return p;
203         }
204         data = p->avl_data;
205
206         /* If this node has two children, swap so we are deleting a node with
207          * at most one child.
208          */
209         if ( p->avl_link[0] && p->avl_link[1] ) {
210
211                 /* find the immediate predecessor <q> */
212                 q = p->avl_link[0];
213                 side = depth;
214                 pdir[depth++] = 0;
215                 while (q->avl_link[1]) {
216                         pdir[depth] = 1;
217                         pptr[depth++] = q;
218                         q = q->avl_link[1];
219                 }
220                 /* swap links */
221                 r = p->avl_link[0];
222                 p->avl_link[0] = q->avl_link[0];
223                 q->avl_link[0] = r;
224
225                 q->avl_link[1] = p->avl_link[1];
226                 p->avl_link[1] = NULL;
227
228                 q->avl_bf = p->avl_bf;
229
230                 /* fix stack positions: old parent of p points to q */
231                 pptr[side] = q;
232                 if ( side ) {
233                         --side;
234                         r = pptr[side];
235                         r->avl_link[pdir[side]] = q;
236                 } else {
237                         *root = q;
238                 }
239                 /* new parent of p points to p */
240                 if ( depth > 1 ) {
241                         r = pptr[depth-1];
242                         r->avl_link[1] = p;
243                 } else {
244                         q->avl_link[0] = p;
245                 }
246         }
247
248         /* now <p> has at most one child, get it */
249         q = p->avl_link[0];
250
251         ber_memfree( p );
252
253         if ( !depth ) {
254                 *root = q;
255                 return data;
256         }
257
258         /* set the child into p's parent */
259         depth--;
260         p = pptr[depth];
261         side = pdir[depth];
262         p->avl_link[side] = q;
263
264         top = NULL;
265         shorter = 1;
266   
267         while ( shorter ) {
268                 p = pptr[depth];
269                 side = pdir[depth];
270                 nside = !side;
271                 side_bf = avl_bfs[side];
272
273                 /* case 1: height unchanged */
274                 if ( p->avl_bf == EH ) {
275                         /* Tree is now heavier on opposite side */
276                         p->avl_bf = avl_bfs[nside];
277                         shorter = 0;
278                   
279                 } else if ( p->avl_bf == side_bf ) {
280                 /* case 2: taller subtree shortened, height reduced */
281                         p->avl_bf = EH;
282                 } else {
283                 /* case 3: shorter subtree shortened */
284                         if ( depth )
285                                 top = pptr[depth-1]; /* p->parent; */
286                         else
287                                 top = NULL;
288                         /* set <q> to the taller of the two subtrees of <p> */
289                         q = p->avl_link[nside];
290                         if ( q->avl_bf == EH ) {
291                                 /* case 3a: height unchanged, single rotate */
292                                 p->avl_link[nside] = q->avl_link[side];
293                                 q->avl_link[side] = p;
294                                 shorter = 0;
295                                 q->avl_bf = side_bf;
296                                 p->avl_bf = (- side_bf);
297
298                         } else if ( q->avl_bf == p->avl_bf ) {
299                                 /* case 3b: height reduced, single rotate */
300                                 p->avl_link[nside] = q->avl_link[side];
301                                 q->avl_link[side] = p;
302                                 shorter = 1;
303                                 q->avl_bf = EH;
304                                 p->avl_bf = EH;
305
306                         } else {
307                                 /* case 3c: height reduced, balance factors opposite */
308                                 r = q->avl_link[side];
309                                 q->avl_link[side] = r->avl_link[nside];
310                                 r->avl_link[nside] = q;
311
312                                 p->avl_link[nside] = r->avl_link[side];
313                                 r->avl_link[side] = p;
314
315                                 if ( r->avl_bf == side_bf ) {
316                                         q->avl_bf = (- side_bf);
317                                         p->avl_bf = EH;
318                                 } else if ( r->avl_bf == (- side_bf)) {
319                                         q->avl_bf = EH;
320                                         p->avl_bf = side_bf;
321                                 } else {
322                                         q->avl_bf = EH;
323                                         p->avl_bf = EH;
324                                 }
325                                 r->avl_bf = EH;
326                                 q = r;
327                         }
328                         /* a rotation has caused <q> (or <r> in case 3c) to become
329                          * the root.  let <p>'s former parent know this.
330                          */
331                         if ( top == NULL ) {
332                                 *root = q;
333                         } else if (top->avl_link[0] == p) {
334                                 top->avl_link[0] = q;
335                         } else {
336                                 top->avl_link[1] = q;
337                         }
338                         /* end case 3 */
339                         p = q;
340                 }
341                 if ( !depth )
342                         break;
343                 depth--;
344         } /* end while(shorter) */
345
346         return data;
347 }
348
349 static int
350 avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
351 {
352         if ( root == 0 )
353                 return( AVL_NOMORE );
354
355         if ( root->avl_left != 0 )
356                 if ( avl_inapply( root->avl_left, fn, arg, stopflag ) 
357                     == stopflag )
358                         return( stopflag );
359
360         if ( (*fn)( root->avl_data, arg ) == stopflag )
361                 return( stopflag );
362
363         if ( root->avl_right == 0 )
364                 return( AVL_NOMORE );
365         else
366                 return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
367 }
368
369 static int
370 avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
371 {
372         if ( root == 0 )
373                 return( AVL_NOMORE );
374
375         if ( root->avl_left != 0 )
376                 if ( avl_postapply( root->avl_left, fn, arg, stopflag ) 
377                     == stopflag )
378                         return( stopflag );
379
380         if ( root->avl_right != 0 )
381                 if ( avl_postapply( root->avl_right, fn, arg, stopflag ) 
382                     == stopflag )
383                         return( stopflag );
384
385         return( (*fn)( root->avl_data, arg ) );
386 }
387
388 static int
389 avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
390 {
391         if ( root == 0 )
392                 return( AVL_NOMORE );
393
394         if ( (*fn)( root->avl_data, arg ) == stopflag )
395                 return( stopflag );
396
397         if ( root->avl_left != 0 )
398                 if ( avl_preapply( root->avl_left, fn, arg, stopflag ) 
399                     == stopflag )
400                         return( stopflag );
401
402         if ( root->avl_right == 0 )
403                 return( AVL_NOMORE );
404         else
405                 return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
406 }
407
408 /*
409  * avl_apply -- avl tree root is traversed, function fn is called with
410  * arguments arg and the data portion of each node.  if fn returns stopflag,
411  * the traversal is cut short, otherwise it continues.  Do not use -6 as
412  * a stopflag, as this is what is used to indicate the traversal ran out
413  * of nodes.
414  */
415
416 int
417 avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
418 {
419         switch ( type ) {
420         case AVL_INORDER:
421                 return( avl_inapply( root, fn, arg, stopflag ) );
422         case AVL_PREORDER:
423                 return( avl_preapply( root, fn, arg, stopflag ) );
424         case AVL_POSTORDER:
425                 return( avl_postapply( root, fn, arg, stopflag ) );
426         default:
427                 fprintf( stderr, "Invalid traversal type %d\n", type );
428                 return( -1 );
429         }
430
431         /* NOTREACHED */
432 }
433
434 /*
435  * avl_prefixapply - traverse avl tree root, applying function fprefix
436  * to any nodes that match.  fcmp is called with data as its first arg
437  * and the current node's data as its second arg.  it should return
438  * 0 if they match, < 0 if data is less, and > 0 if data is greater.
439  * the idea is to efficiently find all nodes that are prefixes of
440  * some key...  Like avl_apply, this routine also takes a stopflag
441  * and will return prematurely if fmatch returns this value.  Otherwise,
442  * AVL_NOMORE is returned.
443  */
444
445 int
446 avl_prefixapply(
447     Avlnode     *root,
448     void*       data,
449     AVL_CMP             fmatch,
450     void*       marg,
451     AVL_CMP             fcmp,
452     void*       carg,
453     int         stopflag
454 )
455 {
456         int     cmp;
457
458         if ( root == 0 )
459                 return( AVL_NOMORE );
460
461         cmp = (*fcmp)( data, root->avl_data /* , carg */);
462         if ( cmp == 0 ) {
463                 if ( (*fmatch)( root->avl_data, marg ) == stopflag )
464                         return( stopflag );
465
466                 if ( root->avl_left != 0 )
467                         if ( avl_prefixapply( root->avl_left, data, fmatch,
468                             marg, fcmp, carg, stopflag ) == stopflag )
469                                 return( stopflag );
470
471                 if ( root->avl_right != 0 )
472                         return( avl_prefixapply( root->avl_right, data, fmatch,
473                             marg, fcmp, carg, stopflag ) );
474                 else
475                         return( AVL_NOMORE );
476
477         } else if ( cmp < 0 ) {
478                 if ( root->avl_left != 0 )
479                         return( avl_prefixapply( root->avl_left, data, fmatch,
480                             marg, fcmp, carg, stopflag ) );
481         } else {
482                 if ( root->avl_right != 0 )
483                         return( avl_prefixapply( root->avl_right, data, fmatch,
484                             marg, fcmp, carg, stopflag ) );
485         }
486
487         return( AVL_NOMORE );
488 }
489
490 /*
491  * avl_free -- traverse avltree root, freeing the memory it is using.
492  * the dfree() is called to free the data portion of each node.  The
493  * number of items actually freed is returned.
494  */
495
496 int
497 avl_free( Avlnode *root, AVL_FREE dfree )
498 {
499         int     nleft, nright;
500
501         if ( root == 0 )
502                 return( 0 );
503
504         nleft = nright = 0;
505         if ( root->avl_left != 0 )
506                 nleft = avl_free( root->avl_left, dfree );
507
508         if ( root->avl_right != 0 )
509                 nright = avl_free( root->avl_right, dfree );
510
511         if ( dfree )
512                 (*dfree)( root->avl_data );
513         ber_memfree( root );
514
515         return( nleft + nright + 1 );
516 }
517
518 /*
519  * avl_find -- search avltree root for a node with data data.  the function
520  * cmp is used to compare things.  it is called with data as its first arg 
521  * and the current node data as its second.  it should return 0 if they match,
522  * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
523  */
524
525 Avlnode *
526 avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
527 {
528         int     cmp;
529
530         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
531                 if ( cmp < 0 )
532                         root = root->avl_left;
533                 else
534                         root = root->avl_right;
535         }
536         return root;
537 }
538
539 void*
540 avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
541 {
542         int     cmp;
543
544         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
545                 if ( cmp < 0 )
546                         root = root->avl_left;
547                 else
548                         root = root->avl_right;
549         }
550
551         return( root ? root->avl_data : 0 );
552 }
553
554 /*
555  * avl_find_lin -- search avltree root linearly for a node with data data. 
556  * the function cmp is used to compare things.  it is called with data as its
557  * first arg and the current node data as its second.  it should return 0 if
558  * they match, non-zero otherwise.
559  */
560
561 void*
562 avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
563 {
564         void*   res;
565
566         if ( root == 0 )
567                 return( NULL );
568
569         if ( (*fcmp)( data, root->avl_data ) == 0 )
570                 return( root->avl_data );
571
572         if ( root->avl_left != 0 )
573                 if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
574                     != NULL )
575                         return( res );
576
577         if ( root->avl_right == 0 )
578                 return( NULL );
579         else
580                 return( avl_find_lin( root->avl_right, data, fcmp ) );
581 }
582
583 /* NON-REENTRANT INTERFACE */
584
585 static void*    *avl_list;
586 static int      avl_maxlist;
587 static int      avl_nextlist;
588
589 #define AVL_GRABSIZE    100
590
591 /* ARGSUSED */
592 static int
593 avl_buildlist( void* data, void* arg )
594 {
595         static int      slots;
596
597         if ( avl_list == (void* *) 0 ) {
598                 avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
599                 slots = AVL_GRABSIZE;
600                 avl_maxlist = 0;
601         } else if ( avl_maxlist == slots ) {
602                 slots += AVL_GRABSIZE;
603                 avl_list = (void* *) ber_memrealloc( (char *) avl_list,
604                     (unsigned) slots * sizeof(void*));
605         }
606
607         avl_list[ avl_maxlist++ ] = data;
608
609         return( 0 );
610 }
611
612 /*
613  * avl_getfirst() and avl_getnext() are provided as alternate tree
614  * traversal methods, to be used when a single function cannot be
615  * provided to be called with every node in the tree.  avl_getfirst()
616  * traverses the tree and builds a linear list of all the nodes,
617  * returning the first node.  avl_getnext() returns the next thing
618  * on the list built by avl_getfirst().  This means that avl_getfirst()
619  * can take a while, and that the tree should not be messed with while
620  * being traversed in this way, and that multiple traversals (even of
621  * different trees) cannot be active at once.
622  */
623
624 void*
625 avl_getfirst( Avlnode *root )
626 {
627         if ( avl_list ) {
628                 ber_memfree( (char *) avl_list);
629                 avl_list = (void* *) 0;
630         }
631         avl_maxlist = 0;
632         avl_nextlist = 0;
633
634         if ( root == 0 )
635                 return( 0 );
636
637         (void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
638
639         return( avl_list[ avl_nextlist++ ] );
640 }
641
642 void*
643 avl_getnext( void )
644 {
645         if ( avl_list == 0 )
646                 return( 0 );
647
648         if ( avl_nextlist == avl_maxlist ) {
649                 ber_memfree( (void*) avl_list);
650                 avl_list = (void* *) 0;
651                 return( 0 );
652         }
653
654         return( avl_list[ avl_nextlist++ ] );
655 }
656
657 /* end non-reentrant code */
658
659
660 int
661 avl_dup_error( void* left, void* right )
662 {
663         return( -1 );
664 }
665
666 int
667 avl_dup_ok( void* left, void* right )
668 {
669         return( 0 );
670 }