From: Howard Chu Date: Wed, 21 Sep 2005 14:45:35 +0000 (+0000) Subject: Add testtavl, add tavl_end and tavl_next. tavl_delete still needs work. X-Git-Tag: OPENLDAP_REL_ENG_2_2_MP~403 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ecc51869550c0da9b6e912dad12feb75a00f08d3;p=openldap Add testtavl, add tavl_end and tavl_next. tavl_delete still needs work. --- diff --git a/libraries/liblutil/Makefile.in b/libraries/liblutil/Makefile.in index f846c20106..65fae592db 100644 --- a/libraries/liblutil/Makefile.in +++ b/libraries/liblutil/Makefile.in @@ -41,6 +41,9 @@ OBJS = base64.o csn.o entropy.o sasl.o signal.o hash.o passfile.o \ testavl: $(XLIBS) testavl.o (LTLINK) -o $@ testavl.o $(LIBS) +testtavl: $(XLIBS) testtavl.o + (LTLINK) -o $@ testtavl.o $(LIBS) + # These rules are for a Mingw32 build, specifically. # It's ok for them to be here because the clean rule is harmless, and # slapdmsg.res won't get built unless it's declared in OBJS. diff --git a/libraries/liblutil/tavl.c b/libraries/liblutil/tavl.c index de5df0baa3..73ab46984d 100644 --- a/libraries/liblutil/tavl.c +++ b/libraries/liblutil/tavl.c @@ -185,8 +185,8 @@ tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup ) void* tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) { - Avlnode *p, *q, *r, *top; - int side, side_bf, shorter, cmp; + Avlnode *p, *q, *r, *s, *top; + int side, side_bf, shorter, nside; /* parent stack */ Avlnode *pptr[sizeof(void *)*8]; @@ -199,24 +199,24 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) p = *root; while (1) { - cmp = fcmp( data, p->avl_data ); - if ( !cmp ) + side = fcmp( data, p->avl_data ); + if ( !side ) break; - cmp = ( cmp > 0 ); - pdir[depth] = cmp; + side = ( side > 0 ); + pdir[depth] = side; pptr[depth++] = p; - p = avl_child( p, cmp ); - if ( p == NULL ) + if ( p->avl_bits[side] == AVL_THREAD ) return NULL; + p = p->avl_link[side]; } + data = p->avl_data; /* If this node has two children, swap so we are deleting a node with * at most one child. */ if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD && p->avl_link[0] && p->avl_link[1] ) { - void *temp; /* find the immediate predecessor */ q = p->avl_link[0]; @@ -228,22 +228,25 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) q = q->avl_link[1]; } /* swap */ - temp = p->avl_data; p->avl_data = q->avl_data; - q->avl_data = temp; p = q; } /* now

has at most one child, get it */ if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) { q = p->avl_link[0]; + /* Preserve thread continuity */ + r = p->avl_link[1]; + nside = 1; } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) { q = p->avl_link[1]; + r = p->avl_link[0]; + nside = 0; } else { q = NULL; + /* No children, no thread to preserve */ } - data = p->avl_data; ber_memfree( p ); if ( !depth ) { @@ -256,23 +259,27 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) side = pdir[depth]; p = pptr[depth]; p->avl_link[side] = q; - side_bf = avl_bfs[side]; - top = NULL; /* Update child thread */ if ( q ) { - while ( q->avl_bits[!side] == AVL_CHILD ) - q = q->avl_link[!side]; - q->avl_link[!side] = p; + for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside]; + q = q->avl_link[nside] ) ; + q->avl_link[nside] = r; + } else { + /* NULL links are always threads */ + p->avl_bits[side] = AVL_THREAD; } + side_bf = avl_bfs[side]; + top = NULL; shorter = 1; + nside = !side; while ( shorter ) { /* case 1: height unchanged */ if ( p->avl_bf == EH ) { /* Tree is now heavier on opposite side */ - p->avl_bf = avl_bfs[!side]; + p->avl_bf = avl_bfs[nside]; shorter = 0; } else if ( p->avl_bf == side_bf ) { @@ -285,14 +292,14 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) else top = NULL; /* set to the taller of the two subtrees of

*/ - q = p->avl_link[!side]; + q = p->avl_link[nside]; if ( q->avl_bf == EH ) { /* case 3a: height unchanged, single rotate */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; - p->avl_bits[!side] = AVL_THREAD; + p->avl_bits[nside] = AVL_THREAD; } else { - p->avl_link[!side] = q->avl_link[side]; + p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; } shorter = 0; @@ -303,9 +310,9 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) /* case 3b: height reduced, single rotate */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; - p->avl_bits[!side] = AVL_THREAD; + p->avl_bits[nside] = AVL_THREAD; } else { - p->avl_link[!side] = q->avl_link[side]; + p->avl_link[nside] = q->avl_link[side]; q->avl_link[side] = p; } shorter = 1; @@ -315,20 +322,20 @@ tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) } else { /* case 3c: height reduced, balance factors opposite */ r = q->avl_link[side]; - if ( r->avl_bits[!side] == AVL_THREAD ) { - r->avl_bits[!side] = AVL_CHILD; + if ( r->avl_bits[nside] == AVL_THREAD ) { + r->avl_bits[nside] = AVL_CHILD; q->avl_bits[side] = AVL_THREAD; } else { - q->avl_link[side] = r->avl_link[!side]; - r->avl_link[!side] = q; + q->avl_link[side] = r->avl_link[nside]; + r->avl_link[nside] = q; } if ( r->avl_bits[side] == AVL_THREAD ) { r->avl_bits[side] = AVL_CHILD; - p->avl_bits[!side] = AVL_THREAD; - p->avl_link[!side] = r; + p->avl_bits[nside] = AVL_THREAD; + p->avl_link[nside] = r; } else { - p->avl_link[!side] = r->avl_link[side]; + p->avl_link[nside] = r->avl_link[side]; r->avl_link[side] = p; } @@ -407,10 +414,8 @@ tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp ) int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { - if ( cmp < 0 ) - root = avl_lchild( root ); - else - root = avl_rchild( root ); + cmp = cmp > 0; + root = avl_child( root, cmp ); } return root; } @@ -421,11 +426,37 @@ tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp ) int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { - if ( cmp < 0 ) - root = avl_lchild( root ); - else - root = avl_rchild( root ); + cmp = cmp > 0; + root = avl_child( root, cmp ); } return( root ? root->avl_data : 0 ); } + +/* Return the leftmost or rightmost node in the tree */ +Avlnode * +tavl_end( Avlnode *root, int dir ) +{ + if ( root ) { + while ( root->avl_bits[dir] == AVL_CHILD ) + root = root->avl_link[dir]; + } + return root; +} + +/* Return the next node in the given direction */ +Avlnode * +tavl_next( Avlnode *root, int dir ) +{ + if ( root ) { + int c = root->avl_bits[dir]; + + root = root->avl_link[dir]; + if ( c == AVL_CHILD ) { + dir ^= 1; + while ( root->avl_bits[dir] == AVL_CHILD ) + root = root->avl_link[dir]; + } + } + return root; +} diff --git a/libraries/liblutil/testtavl.c b/libraries/liblutil/testtavl.c new file mode 100644 index 0000000000..90710ae242 --- /dev/null +++ b/libraries/liblutil/testtavl.c @@ -0,0 +1,158 @@ +/* testavl.c - Test Tim Howes AVL code */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2005 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* Portions Copyright (c) 1993 Regents of the University of Michigan. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of Michigan at Ann Arbor. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ +/* ACKNOWLEDGEMENTS: + * This work was originally developed by the University of Michigan + * (as part of U-MICH LDAP). Additional contributors include + * Howard Chu + */ + +#include "portable.h" + +#include + +#include +#include + +#define AVL_INTERNAL +#include "avl.h" + +static void ravl_print LDAP_P(( Avlnode *root, int depth, int thread )); +static void myprint LDAP_P(( Avlnode *root )); +static int avl_strcmp LDAP_P(( const void *s, const void *t )); + +int +main( int argc, char **argv ) +{ + Avlnode *tree = NULL, *n; + char command[ 10 ]; + char name[ 80 ]; + char *p; + + printf( "> " ); + while ( fgets( command, sizeof( command ), stdin ) != NULL ) { + switch( *command ) { + case 'n': /* new tree */ + ( void ) tavl_free( tree, free ); + tree = NULL; + break; + case 'p': /* print */ + ( void ) myprint( tree ); + break; + case 't': /* traverse with first, next */ + printf( "***\n" ); + for ( n = tavl_end( tree, TAVL_DIR_LEFT ); + n != NULL; + n = tavl_next( n, TAVL_DIR_RIGHT )) + printf( "%s\n", n->avl_data ); + printf( "***\n" ); + break; + case 'f': /* find */ + printf( "data? " ); + if ( fgets( name, sizeof( name ), stdin ) == NULL ) + exit( EXIT_SUCCESS ); + name[ strlen( name ) - 1 ] = '\0'; + if ( (p = (char *) tavl_find( tree, name, avl_strcmp )) + == NULL ) + printf( "Not found.\n\n" ); + else + printf( "%s\n\n", p ); + break; + case 'i': /* insert */ + printf( "data? " ); + if ( fgets( name, sizeof( name ), stdin ) == NULL ) + exit( EXIT_SUCCESS ); + name[ strlen( name ) - 1 ] = '\0'; + if ( tavl_insert( &tree, strdup( name ), avl_strcmp, + avl_dup_error ) != 0 ) + printf( "\nNot inserted!\n" ); + break; + case 'd': /* delete */ + printf( "data? " ); + if ( fgets( name, sizeof( name ), stdin ) == NULL ) + exit( EXIT_SUCCESS ); + name[ strlen( name ) - 1 ] = '\0'; + if ( tavl_delete( &tree, name, avl_strcmp ) == NULL ) + printf( "\nNot found!\n" ); + break; + case 'q': /* quit */ + exit( EXIT_SUCCESS ); + break; + case '\n': + break; + default: + printf("Commands: insert, delete, print, new, quit\n"); + } + + printf( "> " ); + } + + return( 0 ); +} + +static const char bfc_array[] = "\\-/"; +static const char *bfcs = bfc_array+1; + +static void ravl_print( Avlnode *root, int depth, int thread ) +{ + int i; + + if ( root && !thread ) + ravl_print( root->avl_link[1], depth+1, root->avl_bits[1] == AVL_THREAD ); + + for ( i = 0; i < depth; i++ ) + printf( " " ); + if ( thread ) + printf( "~" ); + else if ( root ) + printf( "%c", bfcs[root->avl_bf] ); + else + printf( " " ); + if ( !root) { + printf( ".\n" ); + return; + } + printf( "%s\n", (char *) root->avl_data ); + + if ( !thread ) + ravl_print( root->avl_link[0], depth+1, root->avl_bits[0] == AVL_THREAD ); +} + +static void myprint( Avlnode *root ) +{ + printf( "********\n" ); + + if ( root == 0 ) + printf( "\tNULL\n" ); + else + ravl_print( root, 0, 0 ); + + printf( "********\n" ); +} + +static int avl_strcmp( const void *s, const void *t ) +{ + return strcmp( s, t ); +}