Make set iteratively clear

Previously, the set AVL tree would recursively clear. Now, it iteratively clears.
This commit is contained in:
Bailey Thompson
2017-12-31 02:46:23 -05:00
committed by GitHub
parent 4d665a7e4d
commit dcdb8c9c95
2 changed files with 140 additions and 64 deletions

View File

@@ -369,7 +369,7 @@ static struct node *set_repair_pivot(set me,
* Balances the AVL tree on deletion. * Balances the AVL tree on deletion.
*/ */
static void set_delete_balance(set me, static void set_delete_balance(set me,
struct node *const item, struct node *item,
const bool is_left_deleted) const bool is_left_deleted)
{ {
if (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} // Must re-balance if not in {-1, 0, 1}
if (item->balance > 1 || item->balance < -1) { if (item->balance > 1 || item->balance < -1) {
const struct node *const child = item = set_repair_pivot(me, item, is_left_deleted);
set_repair_pivot(me, item, is_left_deleted); if (item->parent == NULL || item->balance == -1 || item->balance == 1) {
const struct node *const parent = child->parent;
if (parent == NULL || child->balance == -1 || child->balance == 1) {
return; return;
} }
} }
@@ -411,9 +409,10 @@ static void set_delete_balance(set me,
if (parent == NULL || child->balance == -1 || child->balance == 1) { if (parent == NULL || child->balance == -1 || child->balance == 1) {
return; 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) static void set_remove_two_children(set me, const struct node *const traverse)
{ {
bool is_left_deleted;
struct node *item; 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; 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 { } else {
item = traverse->right->left; item = traverse->right->left;
while (item->left != NULL) { while (item->left != NULL) {
item = item->left; item = item->left;
} }
parent = item->parent;
item->balance = traverse->balance;
item->parent->left = item->right; 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 = traverse->right;
item->right->parent = item; item->right->parent = item;
is_left_deleted = true; item->parent = traverse->parent;
} }
struct node *parent = item->parent; if (traverse->parent == NULL) {
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) {
me->root = item; 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); 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. * 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) { if (traverse == NULL) {
return false; return false;
} }
if (traverse->left == NULL && traverse->right == NULL) { set_remove_element(me, traverse);
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--;
return true; 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. * Clears the elements from the set.
* *
@@ -563,10 +560,8 @@ static void set_clear_root(struct node *const root)
*/ */
void set_clear(set me) void set_clear(set me)
{ {
if (me->root != NULL) { while (me->root != NULL) {
set_clear_root(me->root); set_remove_element(me, me->root);
me->root = NULL;
me->size = 0;
} }
} }

105
tst/set.c
View File

@@ -32,7 +32,6 @@ struct node {
*/ */
static int set_verify_recursive(struct node *const item) static int set_verify_recursive(struct node *const item)
{ {
#ifdef LONG_TEST
if (item == NULL) { if (item == NULL) {
return 0; return 0;
} }
@@ -54,42 +53,55 @@ static int set_verify_recursive(struct node *const item)
assert(item->right->parent->key == item->key); assert(item->right->parent->key == item->key);
} }
return max + 1; 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 #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); const int ret = set_add(me, key);
set_verify_recursive(me->root); set_verify(me);
return ret; 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); const bool ret = set_contains(me, key);
set_verify_recursive(me->root); set_verify(me);
return ret; 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); const bool ret = set_remove(me, key);
set_verify_recursive(me->root); set_verify(me);
return ret; return ret;
} }
static void stub_set_clear(set me) static void stub_set_clear(set me)
{ {
set_clear(me); set_clear(me);
set_verify_recursive(me->root); set_verify(me);
} }
static set stub_set_destroy(set me) static set stub_set_destroy(set me)
{ {
set ret = set_destroy(me); set ret = set_destroy(me);
set_verify_recursive(me->root); set_verify(me);
return ret; return ret;
} }
@@ -144,6 +156,75 @@ void test_set(void)
b = 0xdeadbeef; b = 0xdeadbeef;
stub_set_contains(a, &b); stub_set_contains(a, &b);
stub_set_clear(a); 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; int count = 0;
bool flip = false; bool flip = false;
for (int i = 1234; i < 82400; i++) { for (int i = 1234; i < 82400; i++) {
@@ -345,7 +426,7 @@ void test_set(void)
tmp = 7; tmp = 7;
assert(stub_set_contains(a, &tmp)); assert(stub_set_contains(a, &tmp));
stub_set_destroy(a); stub_set_destroy(a);
// Replace two sided two children // Replace two sided two children.
a = set_init(sizeof(int), compare_int); a = set_init(sizeof(int), compare_int);
b = 5; b = 5;
stub_set_add(a, &b); stub_set_add(a, &b);