/* * Template for performing a double rotation --- * * sign > 0: Rotate counterclockwise (left) rooted at B, then * clockwise (right) rooted at A: * * P? P? P? * | | | * A A E * / \ / \ / \ * B C? => E C? => B A * / \ / \ / \ / \ * D? E B G? D? F?G? C? * / \ / \ * F? G? D? F? * * (nodes marked with ? may not exist) * * sign < 0: Rotate clockwise (right) rooted at B, then * counterclockwise (left) rooted at A: * * P? P? P? * | | | * A A E * / \ / \ / \ * C? B => C? E => A B * / \ / \ / \ / \ * E D? G? B C? G?F? D? * / \ / \ * G? F? F? D? * * Returns a pointer to E and updates balance factors. Except for those * two things, this function is equivalent to: * avl_rotate(root_ptr, B, -sign); * avl_rotate(root_ptr, A, +sign); * * See comment in avl_handle_subtree_growth() for explanation of balance * factor updates. */ static AVL_INLINE struct avl_tree_node * avl_do_double_rotate(struct avl_tree_node ** const root_ptr, struct avl_tree_node * const B, struct avl_tree_node * const A, const int sign) { struct avl_tree_node * const E = avl_get_child(B, +sign); struct avl_tree_node * const F = avl_get_child(E, -sign); struct avl_tree_node * const G = avl_get_child(E, +sign); struct avl_tree_node * const P = avl_get_parent(A); const int e = avl_get_balance_factor(E); avl_set_child(A, -sign, G); avl_set_parent_balance(A, E, ((sign * e >= 0) ? 0 : -e)); avl_set_child(B, +sign, F); avl_set_parent_balance(B, E, ((sign * e <= 0) ? 0 : -e)); avl_set_child(E, +sign, A); avl_set_child(E, -sign, B); avl_set_parent_balance(E, P, 0); if (G) avl_set_parent(G, A); if (F) avl_set_parent(F, B); avl_replace_child(root_ptr, P, A, E); return E; }
/* * Removes an item from the specified AVL tree. * * @root_ptr * Location of the AVL tree's root pointer. Indirection is needed * because the root node may change if the tree needed to be rebalanced * because of the deletion or if @node was the root node. * * @node * Pointer to the `struct avl_tree_node' embedded in the item to * remove from the tree. * * Note: This function *only* removes the node and rebalances the tree. * It does not free any memory, nor does it do the equivalent of * avl_tree_node_set_unlinked(). */ void avl_tree_remove(struct avl_tree_node **root_ptr, struct avl_tree_node *node) { struct avl_tree_node *parent; bool left_deleted = false; if (node->left && node->right) { /* @node is fully internal, with two children. Swap it * with its in-order successor (which must exist in the * right subtree of @node and can have, at most, a right * child), then unlink @node. */ parent = avl_tree_swap_with_successor(root_ptr, node, &left_deleted); /* @parent is now the parent of what was @node's in-order * successor. It cannot be NULL, since @node itself was * an ancestor of its in-order successor. * @left_deleted has been set to %true if @node's * in-order successor was the left child of @parent, * otherwise %false. */ } else { struct avl_tree_node *child; /* @node is missing at least one child. Unlink it. Set * @parent to @node's parent, and set @left_deleted to * reflect which child of @parent @node was. Or, if * @node was the root node, simply update the root node * and return. */ child = node->left ? node->left : node->right; parent = avl_get_parent(node); if (parent) { if (node == parent->left) { parent->left = child; left_deleted = true; } else { parent->right = child; left_deleted = false; } if (child) avl_set_parent(child, parent); } else { if (child) avl_set_parent(child, parent); *root_ptr = child; return; } } /* Rebalance the tree. */ do { if (left_deleted) parent = avl_handle_subtree_shrink(root_ptr, parent, +1, &left_deleted); else parent = avl_handle_subtree_shrink(root_ptr, parent, -1, &left_deleted); } while (parent); }
/* * Template for performing a single rotation --- * * sign > 0: Rotate clockwise (right) rooted at A: * * P? P? * | | * A B * / \ / \ * B C? => D? A * / \ / \ * D? E? E? C? * * (nodes marked with ? may not exist) * * sign < 0: Rotate counterclockwise (left) rooted at A: * * P? P? * | | * A B * / \ / \ * C? B => A D? * / \ / \ * E? D? C? E? * * This updates pointers but not balance factors! */ static AVL_INLINE void avl_rotate(struct avl_tree_node ** const root_ptr, struct avl_tree_node * const A, const int sign) { struct avl_tree_node * const B = avl_get_child(A, -sign); struct avl_tree_node * const E = avl_get_child(B, +sign); struct avl_tree_node * const P = avl_get_parent(A); avl_set_child(A, -sign, E); avl_set_parent(A, B); avl_set_child(B, +sign, A); avl_set_parent(B, P); if (E) avl_set_parent(E, A); avl_replace_child(root_ptr, P, A, B); }
INLINE struct avl_node* _rotate_RR(struct avl_node *parent, int parent_bf, int *child_bf, int *height_delta) // MUST ensure that parent_bf >= 0 { int p_left, c_left, c_right; struct avl_node *child = parent->right; __AVL_DEBUG_RR(parent, child, parent_bf, *child_bf); c_left = (child->left)?(1):(0); c_right = (child->right)?(1):(0); if (*child_bf < 0) { // child->left > child->right c_left = c_right - (*child_bf); p_left = c_left + 1 - parent_bf; if (height_delta) *height_delta = max(c_right, max(c_left, p_left)+1) - (c_left + 1); } else { // child->left <= child->right c_right = c_left + (*child_bf); p_left = c_right + 1 - parent_bf; if (height_delta) *height_delta = max(c_right, max(c_left, p_left)+1) - (c_right + 1); } *child_bf = c_right - (max(c_left, p_left) + 1); avl_set_bf(parent, c_left - p_left); parent->right = child->left; if (child->left) avl_set_parent(child->left, parent); child->left = parent; avl_set_parent(child, avl_parent(parent)); avl_set_parent(parent, child); return child; }
/* Swaps node X, which must have 2 children, with its in-order successor, then * unlinks node X. Returns the parent of X just before unlinking, without its * balance factor having been updated to account for the unlink. */ static AVL_INLINE struct avl_tree_node * avl_tree_swap_with_successor(struct avl_tree_node **root_ptr, struct avl_tree_node *X, bool *left_deleted_ret) { struct avl_tree_node *Y, *ret; Y = X->right; if (!Y->left) { /* * P? P? P? * | | | * X Y Y * / \ / \ / \ * A Y => A X => A B? * / \ / \ * (0) B? (0) B? * * [ X unlinked, Y returned ] */ ret = Y; *left_deleted_ret = false; } else { struct avl_tree_node *Q; do { Q = Y; Y = Y->left; } while (Y->left); /* * P? P? P? * | | | * X Y Y * / \ / \ / \ * A ... => A ... => A ... * | | | * Q Q Q * / / / * Y X B? * / \ / \ * (0) B? (0) B? * * * [ X unlinked, Q returned ] */ Q->left = Y->right; if (Q->left) avl_set_parent(Q->left, Q); Y->right = X->right; avl_set_parent(X->right, Y); ret = Q; *left_deleted_ret = true; } Y->left = X->left; avl_set_parent(X->left, Y); Y->parent_balance = X->parent_balance; avl_replace_child(root_ptr, avl_get_parent(X), X, Y); return ret; }
void avl_remove(struct avl_tree *tree, struct avl_node *node) { __AVL_DEBUG_REMOVE(node); // not found if (node == NULL) return; struct avl_tree right_subtree; struct avl_node *p=NULL,*cur, *next=NULL; int bf = 0, bf_old; #ifdef _AVL_NEXT_POINTER if (node->prev) node->prev->next = node->next; if (node->next) node->next->prev = node->prev; #endif // find smallest node in right sub-tree right_subtree.root = node->right; next = avl_first(&right_subtree); if (next) { // 1. NEXT exists if (avl_parent(next)) { if (avl_parent(next) != node) { // NODE is not NEXT's direct parent // MUST ensure NEXT should be *left child* of its parent // MUST ensure NEXT doesn't have right child avl_parent(next)->left = next->right; if (next->right) avl_set_parent(next->right, avl_parent(next)); } } if (avl_parent(node)) { // replace NODE by NEXT if (avl_parent(node)->left == node) { avl_parent(node)->left = next; } else { avl_parent(node)->right = next; } } // re-link pointers if (node->right != next) { next->right = node->right; if (node->right) avl_set_parent(node->right, next); cur = avl_parent(next); bf = 1; }else{ cur = next; bf = -1; } next->left = node->left; if (node->left) avl_set_parent(node->left, next); avl_set_parent(next, avl_parent(node)); // inherit NODE's balance factor avl_set_bf(next, avl_bf(node)); } else { // 2. NEXT == NULL (only when there's no right sub-tree) p = avl_parent(node); if (p) { if (p->left == node) { p->left = node->left; bf = 1; } else { p->right = node->left; bf = -1; } } if (node->left) avl_set_parent(node->left, p); cur = avl_parent(node); } // reset root if (tree->root == node) { tree->root = next; if (next == NULL) { if (node->left) tree->root = node->left; } } // recursive balancing process .. scan from CUR to root while(cur) { p = avl_parent(cur); if (p) { // if parent exists bf_old = avl_bf(cur); if (p->right == cur) { cur = _balance_tree(cur, bf); p->right = cur; }else { cur = _balance_tree(cur, bf); p->left = cur; } // calculate balance facter BF for parent if (cur->left == NULL && cur->right == NULL) { // leaf node if (p->left == cur) bf = 1; else bf = -1; } else { // index ndoe bf = 0; if (_abs(bf_old) > _abs(avl_bf(cur))) { // if ABS of balance factor decreases // cascade to parent if (p->left == cur) bf = 1; else bf = -1; } } } else if(cur == tree->root){ tree->root = _balance_tree(tree->root, bf); break; } if (bf == 0) break; cur = p; } __AVL_DEBUG_DISPLAY(tree); }
struct avl_node* avl_insert(struct avl_tree *tree, struct avl_node *node, avl_cmp_func *func) { __AVL_DEBUG_INSERT(node); struct avl_node *p=NULL,*cur; int cmp, bf, bf_old; cur = tree->root; while(cur) { cmp = func(cur, node, tree->aux); p = cur; if(cmp > 0) { cur = cur->left; }else if (cmp < 0){ cur = cur->right; }else { // duplicated key -> return return cur; } } avl_set_parent(node, p); avl_set_bf(node, 0); node->left = node->right = NULL; #ifdef _AVL_NEXT_POINTER node->prev = node->next = NULL; #endif // P is parent node of CUR if(p) { if(func(p, node, tree->aux) > 0) { p->left = node; #ifdef _AVL_NEXT_POINTER node->next = p; node->prev = p->prev; if (p->prev) p->prev->next = node; p->prev = node; #endif }else { p->right = node; #ifdef _AVL_NEXT_POINTER node->prev = p; node->next = p->next; if (p->next) p->next->prev = node; p->next = node; #endif } } else { // no parent .. make NODE as root tree->root = node; } // recursive balancing process .. scan from leaf to root bf = 0; while(node) { p = avl_parent(node); if (p) { // if parent exists bf_old = avl_bf(node); if (p->right == node) { node = _balance_tree(node, bf); p->right = node; }else { node = _balance_tree(node, bf); p->left = node; } // calculate balance facter BF for parent if (node->left == NULL && node->right == NULL) { // leaf node if (p->left == node) bf = -1; else bf = 1; } else { // index ndoe bf = 0; if (_abs(bf_old) < _abs(avl_bf(node))) { // if ABS of balance factor increases // cascade to parent if (p->left == node) bf = -1; else bf = 1; } } } else if(node == tree->root){ tree->root = _balance_tree(tree->root, bf); break; } if (bf == 0) break; node = p; } __AVL_DEBUG_DISPLAY(tree); return node; }