*/ q = p->avl_link[0]; side = depth; pdir[depth++] = 0; while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) { pdir[depth] = 1; pptr[depth++] = q; q = q->avl_link[1]; } /* 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] = q; p->avl_bits[0] = q->avl_bits[0]; p->avl_bits[1] = q->avl_bits[1]; q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD; 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; } /* fix right subtree: successor of p points to q */ r = q->avl_link[1]; while ( r->avl_bits[0] == AVL_CHILD && r->avl_link[0] ) r = r->avl_link[0]; r->avl_link[0] = q; } /* nowhas 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; if ( depth > 0 ) r = p->avl_link[pdir[depth-1]]; else r = NULL; } ber_memfree( p ); /* Update child thread */ if ( q ) { for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside]; q = q->avl_link[nside] ) ; q->avl_link[nside] = r; } if ( !depth ) { *root = q; return data; } /* set the child into p's parent */ depth--; p = pptr[depth]; side = pdir[depth]; p->avl_link[side] = q; if ( !q ) { p->avl_bits[side] = AVL_THREAD; p->avl_link[side] = r; } 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 */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; } else { 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 */ if ( q->avl_bits[side] == AVL_THREAD ) { q->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; } else { 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]; 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[nside]; r->avl_link[nside] = q; } if ( r->avl_bits[side] == AVL_THREAD ) { r->avl_bits[side] = AVL_CHILD; p->avl_bits[nside] = AVL_THREAD; p->avl_link[nside] = r; } else { 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; } /* * ldap_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 ldap_tavl_free( TAvlnode *root, AVL_FREE dfree ) { int nleft, nright; if ( root == 0 ) return( 0 ); nleft = ldap_tavl_free( ldap_avl_lchild( root ), dfree ); nright = ldap_tavl_free( ldap_avl_rchild( root ), dfree ); if ( dfree ) (*dfree)( root->avl_data ); ber_memfree( root ); return( nleft + nright + 1 ); } /* * ldap_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. */ /* * ldap_tavl_find2 - returns TAvlnode instead of data pointer. * ldap_tavl_find3 - as above, but returns TAvlnode even if no match is found. * also set *ret = last comparison result, or -1 if root == NULL. */ TAvlnode * ldap_tavl_find3( TAvlnode *root, const void *data, AVL_CMP fcmp, int *ret ) { int cmp = -1, dir; TAvlnode *prev = root; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { prev = root; dir = cmp > 0; root = ldap_avl_child( root, dir ); } *ret = cmp; return root ? root : prev; } TAvlnode * ldap_tavl_find2( TAvlnode *root, const void *data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = ldap_avl_child( root, cmp ); } return root; } void* ldap_tavl_find( TAvlnode *root, const void* data, AVL_CMP fcmp ) { int cmp; while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) { cmp = cmp > 0; root = ldap_avl_child( root, cmp ); } return( root ? root->avl_data : 0 ); } /* Return the leftmost or rightmost node in the tree */ TAvlnode * ldap_tavl_end( TAvlnode *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 */ TAvlnode * ldap_tavl_next( TAvlnode *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; }