From dcdb8c9c9534fb66f0001d7c72f518550320bd31 Mon Sep 17 00:00:00 2001 From: Bailey Thompson Date: Sun, 31 Dec 2017 02:46:23 -0500 Subject: [PATCH] Make set iteratively clear Previously, the set AVL tree would recursively clear. Now, it iteratively clears. --- src/set.c | 99 ++++++++++++++++++++++++-------------------------- tst/set.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 140 insertions(+), 64 deletions(-) diff --git a/src/set.c b/src/set.c index 0d740f6..d07782a 100644 --- a/src/set.c +++ b/src/set.c @@ -369,7 +369,7 @@ static struct node *set_repair_pivot(set me, * Balances the AVL tree on deletion. */ static void set_delete_balance(set me, - struct node *const item, + struct node *item, const bool is_left_deleted) { if (is_left_deleted) { @@ -383,10 +383,8 @@ static void set_delete_balance(set me, } // Must re-balance if not in {-1, 0, 1} if (item->balance > 1 || item->balance < -1) { - const struct node *const child = - set_repair_pivot(me, item, is_left_deleted); - const struct node *const parent = child->parent; - if (parent == NULL || child->balance == -1 || child->balance == 1) { + item = set_repair_pivot(me, item, is_left_deleted); + if (item->parent == NULL || item->balance == -1 || item->balance == 1) { return; } } @@ -411,9 +409,10 @@ static void set_delete_balance(set me, if (parent == NULL || child->balance == -1 || child->balance == 1) { return; } + } else { + child = parent; + parent = parent->parent; } - child = parent; - parent = parent->parent; } } @@ -482,38 +481,60 @@ static void set_remove_one_child(set me, const struct node *const traverse) */ static void set_remove_two_children(set me, const struct node *const traverse) { - bool is_left_deleted; struct node *item; - if (traverse->right->left == NULL) { + struct node *parent; + const bool is_left_deleted = traverse->right->left != NULL; + if (!is_left_deleted) { item = traverse->right; - is_left_deleted = false; + parent = item; + item->balance = traverse->balance; + item->parent = traverse->parent; + item->left = traverse->left; + item->left->parent = item; } else { item = traverse->right->left; while (item->left != NULL) { item = item->left; } + parent = item->parent; + item->balance = traverse->balance; item->parent->left = item->right; + if (item->right != NULL) { + item->right->parent = item->parent; + } + item->left = traverse->left; + item->left->parent = item; item->right = traverse->right; item->right->parent = item; - is_left_deleted = true; + item->parent = traverse->parent; } - struct node *parent = item->parent; - if (parent == traverse) { - parent = item; - } - item->balance = traverse->balance; - item->parent = traverse->parent; - if (item->parent != NULL) { - item->parent->left = item; - } - item->left = traverse->left; - item->left->parent = item; - if (item->parent == NULL) { + if (traverse->parent == NULL) { me->root = item; + } else if (traverse->parent->left == traverse) { + item->parent->left = item; + } else { + item->parent->right = item; } set_delete_balance(me, parent, is_left_deleted); } +/* + * Removes the element from the set. + */ +static void set_remove_element(set me, struct node *const traverse) +{ + if (traverse->left == NULL && traverse->right == NULL) { + set_remove_no_children(me, traverse); + } else if (traverse->left == NULL || traverse->right == NULL) { + set_remove_one_child(me, traverse); + } else { + set_remove_two_children(me, traverse); + } + free(traverse->key); + free(traverse); + me->size--; +} + /** * Removes the element from the set if it contains it. * @@ -528,34 +549,10 @@ bool set_remove(set me, void *const key) if (traverse == NULL) { return false; } - if (traverse->left == NULL && traverse->right == NULL) { - set_remove_no_children(me, traverse); - } else if (traverse->left == NULL || traverse->right == NULL) { - set_remove_one_child(me, traverse); - } else { - set_remove_two_children(me, traverse); - } - free(traverse->key); - free(traverse); - me->size--; + set_remove_element(me, traverse); return true; } -/* - * Recursively frees the node passed in. - */ -static void set_clear_root(struct node *const root) -{ - if (root->left != NULL) { - set_clear_root(root->left); - } - if (root->right != NULL) { - set_clear_root(root->right); - } - free(root->key); - free(root); -} - /** * Clears the elements from the set. * @@ -563,10 +560,8 @@ static void set_clear_root(struct node *const root) */ void set_clear(set me) { - if (me->root != NULL) { - set_clear_root(me->root); - me->root = NULL; - me->size = 0; + while (me->root != NULL) { + set_remove_element(me, me->root); } } diff --git a/tst/set.c b/tst/set.c index e75e3e1..580d6e9 100644 --- a/tst/set.c +++ b/tst/set.c @@ -32,7 +32,6 @@ struct node { */ static int set_verify_recursive(struct node *const item) { -#ifdef LONG_TEST if (item == NULL) { return 0; } @@ -54,42 +53,55 @@ static int set_verify_recursive(struct node *const item) assert(item->right->parent->key == item->key); } return max + 1; -#else - return 0; +} + +static int set_compute_size(struct node *const item) +{ + if (item == NULL) { + return 0; + } + return 1 + set_compute_size(item->left) + set_compute_size(item->right); +} + +static void set_verify(set me) +{ +#ifdef LONG_TEST + set_verify_recursive(me->root); + assert(set_compute_size(me->root) == set_size(me)); #endif } -static int stub_set_add(set me, void *key) +static int stub_set_add(set me, void *const key) { const int ret = set_add(me, key); - set_verify_recursive(me->root); + set_verify(me); return ret; } -static bool stub_set_contains(set me, void *key) +static bool stub_set_contains(set me, void *const key) { const bool ret = set_contains(me, key); - set_verify_recursive(me->root); + set_verify(me); return ret; } -static bool stub_set_remove(set me, void *key) +static bool stub_set_remove(set me, void *const key) { const bool ret = set_remove(me, key); - set_verify_recursive(me->root); + set_verify(me); return ret; } static void stub_set_clear(set me) { set_clear(me); - set_verify_recursive(me->root); + set_verify(me); } static set stub_set_destroy(set me) { set ret = set_destroy(me); - set_verify_recursive(me->root); + set_verify(me); return ret; } @@ -144,6 +156,75 @@ void test_set(void) b = 0xdeadbeef; stub_set_contains(a, &b); stub_set_clear(a); + // Two children edge case. + b = 8; + stub_set_add(a, &b); + b = 5; + stub_set_add(a, &b); + b = 11; + stub_set_add(a, &b); + b = 2; + stub_set_add(a, &b); + b = 6; + stub_set_add(a, &b); + b = 10; + stub_set_add(a, &b); + b = 15; + stub_set_add(a, &b); + b = 1; + stub_set_add(a, &b); + b = 3; + stub_set_add(a, &b); + b = 4; + stub_set_add(a, &b); + b = 7; + stub_set_add(a, &b); + b = 9; + stub_set_add(a, &b); + b = 12; + stub_set_add(a, &b); + b = 13; + stub_set_add(a, &b); + b = 16; + stub_set_add(a, &b); + b = 14; + stub_set_add(a, &b); + stub_set_clear(a); + // Two children edge case. + b = 8; + stub_set_add(a, &b); + b = 4; + stub_set_add(a, &b); + b = 12; + stub_set_add(a, &b); + b = 2; + stub_set_add(a, &b); + b = 6; + stub_set_add(a, &b); + b = 10; + stub_set_add(a, &b); + b = 15; + stub_set_add(a, &b); + b = 1; + stub_set_add(a, &b); + b = 3; + stub_set_add(a, &b); + b = 5; + stub_set_add(a, &b); + b = 7; + stub_set_add(a, &b); + b = 9; + stub_set_add(a, &b); + b = 11; + stub_set_add(a, &b); + b = 13; + stub_set_add(a, &b); + b = 16; + stub_set_add(a, &b); + b = 14; + stub_set_add(a, &b); + stub_set_clear(a); + // Add a lot of items. int count = 0; bool flip = false; for (int i = 1234; i < 82400; i++) { @@ -345,7 +426,7 @@ void test_set(void) tmp = 7; assert(stub_set_contains(a, &tmp)); stub_set_destroy(a); - // Replace two sided two children + // Replace two sided two children. a = set_init(sizeof(int), compare_int); b = 5; stub_set_add(a, &b);