static bool remove(struct avl *t, void **pp, void **px) { if (*pp == NULL) { *px = NULL; return false; } int cmp = t->cmp(*px, *pp); struct avl_node *p = node(t, *pp); bool dir, shrink; if (cmp == 0) { *px = *pp; dir = p->balance > 0; if (p->child[dir] == NULL) { *pp = p->child[!dir]; return true; } void *swap; shrink = remove_swap(t, &p->child[dir], !dir, &swap); *node(t, swap) = *node(t, *pp); *pp = swap; } else { dir = cmp > 0; shrink = remove(t, &node(t, *pp)->child[dir], px); } return remove_fix(t, pp, dir, shrink); }
static bool remove_swap(struct avl *t, void **pp, bool dir, void **swap) { struct avl_node *p = node(t, *pp); if (p->child[dir] == NULL) { *swap = *pp; *pp = p->child[!dir]; return true; } bool shrink = remove_swap(t, &p->child[dir], dir, swap); return remove_fix(t, pp, dir, shrink); }
bool rbtree_remove(RBTree *tree, const void *key) { assert(!tree->nil->red); RBNode *z = node_get(tree, key); if (z == tree->nil) { return false; } RBNode *y = ((z->left == tree->nil) || (z->right == tree->nil)) ? z : node_next(tree, z); RBNode *x = (y->left == tree->nil) ? y->right : y->left; x->parent = y->parent; if (tree->root == x->parent) { tree->root->left = x; } else { if (y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } } if (z != y) { assert(y != tree->nil); assert(!tree->nil->red); if (!y->red) { remove_fix(tree, x); } y->left = z->left; y->right = z->right; y->parent = z->parent; y->red = z->red; z->left->parent = y; z->right->parent = y; if (z == z->parent->left) { z->parent->left = y; } else { z->parent->right = y; } node_destroy(tree, z); } else { if (!y->red) { remove_fix(tree, x); } node_destroy(tree, y); } assert(!tree->nil->red); tree->size--; return true; }