Add testtavl, add tavl_end and tavl_next. tavl_delete still needs work.

This commit is contained in:
Howard Chu 2005-09-21 14:45:35 +00:00
parent cbb86907a2
commit ecc5186955
3 changed files with 230 additions and 38 deletions

View file

@ -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.

View file

@ -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> */
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 <p> 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 <q> to the taller of the two subtrees of <p> */
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;
}

View file

@ -0,0 +1,158 @@
/* testavl.c - Test Tim Howes AVL code */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* 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
* <http://www.OpenLDAP.org/license.html>.
*/
/* 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 <stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>
#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 );
}