int avl_remove(struct avl *avl, void *value, compare cmp) { struct avl_node *node, **parentp, *min, *left; if ((node = _node_search(avl, value, &parentp, cmp)) == NULL) return -1; retry: /* leaf */ if (!node->left && !node->right) { *parentp = NULL; goto rebalance; } /* single child */ if (!node->left || !node->right) { *parentp = node->left ? node->left : node->right; (*parentp)->parent = node->parent; goto rebalance; } /* double child, find the min node from right subtree */ for (left = node->right; left; left = min->left) { min = left; } _swap_value(node, min); /* now node only have 0 or 1 child */ node = min; parentp = (node == node->parent->left) ? &node->parent->left : &node->parent->right; goto retry; rebalance: _remove_rebalance(avl, node->parent, cmp); avl->count--; free(node); return 0; }
void Tree_remove(Tree _tree, var _key) { struct tree_node *child, *parent, *old, *left, *node, *root = _tree->root; node_color color; var key; if (unlikely(!_tree->root)) { return; } if (_tree->key_type != String) { key = _key; } else { key.str_var = EString_new((char*)_key.str_var); } if (!(node = _search_auxiliary(_tree, key, root, NULL))) { if (_tree->key_type == String) { EString_delete((char*)key.str_var); } return; } if (_tree->key_type == String) { EString_delete((char*)key.str_var); } old = node; if (node->left_node && node->right_node) { node = node->right_node; while ((left = node->left_node) != NULL) { node = left; } child = node->right_node; parent = node->parent_node; color = node->color; if (child) { child->parent_node = parent; } if (parent) { if (parent->left_node == node) { parent->left_node = child; } else { parent->right_node = child; } } else { root = child; } if (node->parent_node == old) { parent = node; } node->parent_node = old->parent_node; node->color = old->color; node->right_node = old->right_node; node->left_node = old->left_node; if (old->parent_node) { if (old->parent_node->left_node == old) { old->parent_node->left_node = node; } else { old->parent_node->right_node = node; } } else { root = node; } old->left_node->parent_node = node; if (old->right_node) { old->right_node->parent_node = node; } } else { if (!node->left_node) { child = node->right_node; } else if (!node->right_node) { child = node->left_node; } parent = node->parent_node; color = node->color; if (child) { child->parent_node = parent; } if (parent) { if (parent->left_node == node) { parent->left_node = child; } else { parent->right_node = child; } } else { root = child; } } if (old != _tree->head) { if (old != _tree->tail) { old->iter_prev->iter_next = old->iter_next; old->iter_next->iter_prev = old->iter_prev; } else { old->iter_prev->iter_next = NULL; _tree->tail = old->iter_prev; } } else { if (old != _tree->tail) { old->iter_next->iter_prev = NULL; _tree->head = old->iter_next; } else { _tree->root = _tree->head = _tree->tail = NULL; _tree->count = 0; return; } } _tree->count--; _tree->free_proc(old); if (color == Black) { root = _remove_rebalance(child, parent, root); } _tree->root = root; }