mirror of
https://github.com/bkthomps/Containers.git
synced 2025-11-16 12:34:47 +00:00
Make set iteratively clear
Previously, the set AVL tree would recursively clear. Now, it iteratively clears.
This commit is contained in:
99
src/set.c
99
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
105
tst/set.c
105
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);
|
||||
|
||||
Reference in New Issue
Block a user