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.
*/
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);
}
}

105
tst/set.c
View File

@@ -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);