static void rbtree_delete_fixup( RBRoot* root, Node* node, Node* parent ) {
Node* other;
while ( ( !node || rb_is_black( node ) ) && node != root->node ) {
if ( parent->left == node ) {
other = parent->right;
if ( rb_is_red( other ) ) {
rb_set_black( other );
rb_set_red( parent );
rbtree_left_rotate( root, parent );
other = parent->right;
}
if ( ( !other->left || rb_is_black( other->left ) ) &&
( !other->right || rb_is_black( other->right ) ) ) {
rb_set_red( other );
node = parent;
parent = rb_parent( node );
} else {
if ( !other->right || rb_is_black( other->right ) ) {
rb_set_black( other->left );
rb_set_red( other );
rbtree_right_rotate( root, other );
other = parent->right;
}
rb_set_color( other, rb_color( parent ) );
rb_set_black( parent );
rb_set_black( other->right );
rbtree_left_rotate( root, parent );
node = root->node;
break;
}
} else {
other = parent->left;
if ( rb_is_red( other ) ) {
rb_set_black( other );
rb_set_red( parent );
rbtree_right_rotate( root, parent );
other = parent->left;
}
if ( ( !other->left || rb_is_black( other->left ) ) &&
( !other->right || rb_is_black( other->right ) ) ) {
rb_set_red( other );
node = parent;
parent = rb_parent( node );
} else {
if ( !other->left || rb_is_black( other->left ) ) {
rb_set_black( other->right );
rb_set_red( other );
rbtree_left_rotate( root, other );
other = parent->left;
}
rb_set_color( other, rb_color( parent ) );
rb_set_black( parent );
rb_set_black( other->left );
rbtree_right_rotate( root, parent );
node = root->node;
break;
}
}
}
if ( node ) rb_set_black( node );
}
void rbtree_delete( RBRoot* root, Node* node ) {
Node *child, *parent;
int color;
if ( ( node->left != NULL ) && ( node->right != NULL ) ) {
Node* replace = node;
replace = replace->right;
while ( replace->left != NULL ) {
replace = replace->left;
}
if ( rb_parent( node ) ) {
if ( rb_parent( node )->left == node ) {
rb_parent( node )->left = replace;
} else {
rb_parent( node )->right = replace;
}
} else {
root->node = replace;
}
child = replace->right;
parent = rb_parent( replace );
color = rb_color( replace );
if ( parent == node ) {
parent = replace;
} else {
if ( child ) rb_set_parent( child, parent );
parent->left = child;
replace->right = node->right;
rb_set_parent( node->right, replace );
}
replace->parent = node->parent;
replace->color = node->color;
replace->left = node->left;
node->left->parent = replace;
if ( color == BLACK ) rbtree_delete_fixup( root, child, parent );
free( node );
return;
}
if ( node->left != NULL ) {
child = node->left;
} else {
child = node->right;
}
parent = node->parent;
color = node->color;
if ( child ) child->parent = parent;
if ( parent ) {
if ( parent->left == node ) {
parent->left = child;
} else {
parent->right = child;
}
} else {
root->node = child;
}
if ( color == BLACK ) rbtree_delete_fixup( root, child, parent );
free( node );
}
void delete_rbtree( RBRoot* root, Type key ) {
Node *z, *node;
if ( ( z = search( root->node, key ) ) != NULL ) rbtree_delete( root, z );
}