*/ + q = p->avl_link[0]; + side = depth; + pdir[depth++] = 0; + while (q->avl_link[1]) { + pdir[depth] = 1; + pptr[depth++] = q; + q = q->avl_link[1]; } - - /* left subtree shorter? */ - if ( shortersubtree ) - *shorter = left_balance( root ); - else - *shorter = 0; - /* go right */ - } else { - if ( (savedata = ravl_delete( &(*root)->avl_right, data, fcmp, - &shortersubtree )) == 0 ) { - *shorter = 0; - return( 0 ); + /* swap links */ + r = p->avl_link[0]; + p->avl_link[0] = q->avl_link[0]; + q->avl_link[0] = r; + + q->avl_link[1] = p->avl_link[1]; + p->avl_link[1] = NULL; + + q->avl_bf = p->avl_bf; + + /* fix stack positions: old parent of p points to q */ + pptr[side] = q; + if ( side ) { + r = pptr[side-1]; + r->avl_link[pdir[side-1]] = q; + } else { + *root = q; + } + /* new parent of p points to p */ + if ( depth-side > 1 ) { + r = pptr[depth-1]; + r->avl_link[1] = p; + } else { + q->avl_link[0] = p; } - - if ( shortersubtree ) - *shorter = right_balance( root ); - else - *shorter = 0; } - return( savedata ); -} + /* nowhas at most one child, get it */ + q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1]; -/* - * avl_delete() - deletes the node containing data (according to fcmp) from - * the avl tree rooted at root. - */ + ber_memfree( p ); -void* -avl_delete( Avlnode **root, void* data, AVL_CMP fcmp ) -{ - int shorter; + if ( !depth ) { + *root = q; + return data; + } - return( ravl_delete( root, data, fcmp, &shorter ) ); + /* set the child into p's parent */ + depth--; + p = pptr[depth]; + side = pdir[depth]; + p->avl_link[side] = q; + + top = NULL; + shorter = 1; + + while ( shorter ) { + p = pptr[depth]; + side = pdir[depth]; + nside = !side; + side_bf = avl_bfs[side]; + + /* case 1: height unchanged */ + if ( p->avl_bf == EH ) { + /* Tree is now heavier on opposite side */ + p->avl_bf = avl_bfs[nside]; + 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[nside]; + if ( q->avl_bf == EH ) { + /* case 3a: height unchanged, single rotate */ + p->avl_link[nside] = 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 */ + p->avl_link[nside] = 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]; + q->avl_link[side] = r->avl_link[nside]; + r->avl_link[nside] = q; + + p->avl_link[nside] = 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--; + } /* end while(shorter) */ + + return data; } static int @@ -644,16 +525,26 @@ avl_free( Avlnode *root, AVL_FREE dfree ) * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2. */ +Avlnode * +avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp ) +{ + int cmp; + + while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { + cmp = cmp > 0; + root = root->avl_link[cmp]; + } + return root; +} + void* avl_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 = root->avl_left; - else - root = root->avl_right; + cmp = cmp > 0; + root = root->avl_link[cmp]; } return( root ? root->avl_data : 0 );