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.
|
* 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
105
tst/set.c
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user