*/ + q = p->avl_link[0]; + pdir[depth] = 0; + pptr[depth++] = p; + while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) { + pdir[depth] = 1; + pptr[depth++] = q; + q = q->avl_link[1]; + } + /* swap */ + temp = p->avl_data; + p->avl_data = q->avl_data; + q->avl_data = temp; + p = q; + } + + /* nowhas at most one child, get it */ + if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) { + q = p->avl_link[0]; + } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) { + q = p->avl_link[1]; + } else { + q = NULL; + } + + data = p->avl_data; + ber_memfree( p ); + + if ( !depth ) { + *root = q; + return data; + } + + /* set the child into p's parent */ + 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; + } + + shorter = 1; + + while ( shorter ) { + /* case 1: height unchanged */ + if ( p->avl_bf == EH ) { + /* Tree is now heavier on opposite side */ + p->avl_bf = avl_bfs[!side]; + shorter = 0; + + } else if ( p->avl_bf == side_bf ) { + /* case 2: taller subtree shortened, height reduced */ + p->avl_bf = EH; + } else { + /* case 3: shorter subtree shortened */ + if ( depth ) + top = pptr[depth-1]; /* p->parent; */ + else + top = NULL; + /* set
to the taller of the two subtrees of*/ + q = p->avl_link[!side]; + 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; + } else { + p->avl_link[!side] = q->avl_link[side]; + q->avl_link[side] = p; + } + shorter = 0; + q->avl_bf = side_bf; + p->avl_bf = (- side_bf); + + } else if ( q->avl_bf == p->avl_bf ) { + /* 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; + } else { + p->avl_link[!side] = q->avl_link[side]; + q->avl_link[side] = p; + } + shorter = 1; + q->avl_bf = EH; + p->avl_bf = EH; + + } 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; + q->avl_bits[side] = AVL_THREAD; + } else { + q->avl_link[side] = r->avl_link[!side]; + r->avl_link[!side] = 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; + } else { + p->avl_link[!side] = r->avl_link[side]; + r->avl_link[side] = p; + } + + if ( r->avl_bf == side_bf ) { + q->avl_bf = (- side_bf); + p->avl_bf = EH; + } else if ( r->avl_bf == (- side_bf)) { + q->avl_bf = EH; + p->avl_bf = side_bf; + } else { + q->avl_bf = EH; + p->avl_bf = EH; + } + r->avl_bf = EH; + q = r; + } + /* a rotation has caused
(orin case 3c) to become + * the root. let 's former parent know this. + */ + if ( top == NULL ) { + *root = q; + } else if (top->avl_link[0] == p) { + top->avl_link[0] = q; + } else { + top->avl_link[1] = q; + } + /* end case 3 */ + p = q; + } + if ( !depth ) + break; + depth--; + p = pptr[depth]; + side = pdir[depth]; + side_bf = avl_bfs[side]; + } /* end while(shorter) */ + + return data; +} + +/* + * tavl_free -- traverse avltree root, freeing the memory it is using. + * the dfree() is called to free the data portion of each node. The + * number of items actually freed is returned. + */ + +int +tavl_free( Avlnode *root, AVL_FREE dfree ) +{ + int nleft, nright; + + if ( root == 0 ) + return( 0 ); + + nleft = tavl_free( avl_lchild( root ), dfree ); + + nright = tavl_free( avl_rchild( root ), dfree ); + + if ( dfree ) + (*dfree)( root->avl_data ); + ber_memfree( root ); + + return( nleft + nright + 1 ); +} + +/* + * tavl_find -- search avltree root for a node with data data. the function + * cmp is used to compare things. it is called with data as its first arg + * and the current node data as its second. it should return 0 if they match, + * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2. + */ + +Avlnode * +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 ); + } + return root; +} + +void* +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 ); + } + + return( root ? root->avl_data : 0 ); +}