diff options
Diffstat (limited to 'collections/map')
-rw-r--r-- | collections/map/map.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/collections/map/map.c b/collections/map/map.c index 701e217..218ec4c 100644 --- a/collections/map/map.c +++ b/collections/map/map.c @@ -394,6 +394,86 @@ void *key; return map_index_aux(root->root, root->cmp, key); } +void* map_remove_aux(root, cmpf, key) +struct map_node **root; +cmp_func cmpf; +void *key; +{ + struct map_node *next, *next_parent, *tmp; + void *ret; + int cmp; + + if (!*root) + return NULL; + + cmp = cmpf(key, (*root)->key); + + if (cmp < 0) { + next = map_remove_aux(&(*root)->left, cmpf, key); + return next; + } + + if (cmp > 0) { + next = map_remove_aux(&(*root)->right, cmpf, key); + return next; + } + + tmp = *root; + + if ((*root)->left && (*root)->right ) { + for (next = (*root)->right; next->left; next = next->left); + } else if ((*root)->left || (*root)->right){ + next = tmp->left ? tmp->left : tmp->right; + } else { + next = NULL; + } + + if (next) { + next_parent = next->parent; + + if (next_parent == tmp) { + if (next->right) + next->right->parent = next_parent; + + next_parent->right = next->right; + next->right = NULL; + } else if (next_parent) { + if (next->right) { + next->right->parent = next_parent; + + next_parent->left = next->right; + next->right = NULL; + } else { + next_parent->left = NULL; + } + } + next->parent = tmp->parent; + next->right = tmp->right; + next->left = tmp->left; + + } + + ret = tmp->val; + + tmp->parent = tmp->right = tmp->left = NULL; + free(tmp); + + *root = next; + + //CHECK BALANCE + return ret; +} + +void* map_remove(root, key) +map *root; +void *key; +{ + if (!root) + return NULL; + + return map_remove_aux(&root->root, root->cmp, key); +} + void map_clear_aux(root) struct map_node *root; { |