rbtree_node_t *rbtree_remove(rbtree_t *tree, rbtree_node_t *node) { rbtree_node_t *remove, *child; if (node->left == tree->sentinel || node->right == tree->sentinel) remove = node; else remove = rbtree_successor(tree, node); if (remove->left != tree->sentinel) child = remove->left; else child = remove->right; child->parent = remove->parent; if (remove->parent == tree->sentinel) tree->root = child; else if (remove == remove->parent->left) remove->parent->left = child; else remove->parent->right = child; if (remove != node) { node->key = remove->key; } if (rbtree_is_black(remove)) rbtree_remove_fixup(tree, child); rbtree_node_delete(remove); return node; }
void rbtree_remove_at(rb_tree * tree, rb_node * node, destructor d) { rb_node *child = NULL; /* In case of deleting the single object stored in the tree, * free the root, thus emptying the tree */ if (tree->isize == 1) { rbnode_destruct(tree->root, d); tree->root = NULL; tree->isize = 0; return; } /* Remove the given node from the tree */ if (node->left && node->right) { /* If the node we want to remove has two children, * find its successor, which is the leftmost child in * its right sub-tree and has at most one child (it * may have a right child). */ rb_node *succ_node = rbnode_minimum(node->right); /* Now physically swap node and its successor. Notice * this may temporarily violate the tree properties, * but we are going to remove node anyway. This way * we have moved node to a position were it is more * convinient to delete it. */ int immediate_succ = (node->right == succ_node); rb_node *succ_parent = succ_node->parent; rb_node *succ_left = succ_node->left; rb_node *succ_right = succ_node->right; rb_color succ_color = succ_node->color; succ_node->parent = node->parent; succ_node->left = node->left; succ_node->right = immediate_succ ? node : node->right; succ_node->color = node->color; node->parent = immediate_succ ? succ_node : succ_parent; node->left = succ_left; node->right = succ_right; node->color = succ_color; if (!immediate_succ) { if (succ_node == node->parent->left) node->parent->left = node; else node->parent->right = node; } if (node->left) node->left->parent = node; if (node->right) node->right->parent = node; if (succ_node->parent) { if (node == succ_node->parent->left) succ_node->parent->left = succ_node; else succ_node->parent->right = succ_node; } else { tree->root = succ_node; } if (succ_node->left) succ_node->left->parent = succ_node; if (succ_node->right) succ_node->right->parent = succ_node; } /* At this stage, the node we are going to remove has at most * one child */ child = (node->left) ? node->left : node->right; /* Splice out the node to be removed, by linking its parent * straight to the removed node's single child. */ if (child) child->parent = node->parent; if (!(node->parent)) { /* If we are deleting the root, make the child the new * tree node */ tree->root = child; } else { /* Link the removed node parent to its child */ if (node == node->parent->left) node->parent->left = child; else node->parent->right = child; } /* Fix-up the red-black properties that may have been damaged: * If we have just removed a black node, the black-depth * property is no longer valid */ if (node->color == black && child) rbtree_remove_fixup(tree, child); /* Delete the un-necessary node (nullify both its children * because the node's destructor is recursive). */ node->left = NULL; node->right = NULL; free(node); /* Decrease the number of objects in the tree */ tree->isize--; }