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];
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];
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 ) {
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 ) {
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;
/* 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;
} 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;
}
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;
}
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;
+}
--- /dev/null
+/* 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 );
+}