fix bug where replaced nodes did not have the same level

This commit is contained in:
Peter McGoron 2024-04-27 21:51:18 -04:00
parent 91640931d9
commit ffc9602661
2 changed files with 147 additions and 16 deletions

View File

@ -1,4 +1,4 @@
Intrusive, single file, imperative AA tree that works on freestanding
Intrusive, single file, C89+ imperative AA tree that works on freestanding
systems.
The implementation is about 300 lines.
@ -38,7 +38,9 @@ own structure and search function like ::
return strcmp(n1->key, n2->key);
}
This is standard, portable C99.
This is standard, portable C89. Intrusive code has the advantage of
requiring only one allocation instead of two, allowing for easier
memory management (i.e. arena memory allocation).
-----------------
Using the Library

157
aatree.h
View File

@ -36,22 +36,56 @@ struct aatree {
unsigned level;
};
/**
* Function signature for node comparison.
*
* This functions returns
* * negative if the key of the first argument is less than the second,
* * 0 if the keys compare equal,
* * and a positive number if the first key is greater than the second.
*/
typedef int (*aatree_cmp_f)(struct aatree *, struct aatree *);
/**
* Insert a node into the tree with root at ``root``. Returns the
* new root of the tree. If there was an element with the same key
* in the tree, the node is placed and the old element is returned
* into ``old``.
*
* Old may be NULL.
*/
AATREE_PREFIX struct aatree *aatree_ins(struct aatree *root,
struct aatree *new_t,
struct aatree **old,
aatree_cmp_f cmp);
/**
* Search the tree for a node that compares equal to "key". The
* "key" node does not need to have any of the values in "struct
* aatree" populated, but it does need to have a valid key.
*
* Returns the node, or NULL if not found.
*/
AATREE_PREFIX struct aatree *aatree_src(struct aatree *root,
struct aatree *key,
aatree_cmp_f cmp);
/**
* Delete a node from the tree starting at "root" that compares equal
* to "key". See "aatree_src" documentation for information on how to
* fill the "key" node. The new root of the tree is returned.
*
* The deleted node is stored in "*match". Match must be a valid pointer
* because it is used in the delete algorithm.
*/
AATREE_PREFIX static struct aatree *aatree_del(struct aatree *root,
struct aatree *key,
struct aatree **match,
aatree_cmp_f cmp);
/**
* Initialize a node.
*/
static void aatree_init(struct aatree *t)
{
t->left = t->right = t->parent = NULL;
@ -87,9 +121,17 @@ static void aatree_replace(struct aatree *old, struct aatree *nw)
{
aatree_relink(old, nw);
if (nw) {
nw->left = old->left;
nw->right = old->right;
nw->level = old->level;
nw->parent = old->parent;
nw->left = old->left;
if (nw->left)
nw->left->parent = nw;
nw->right = old->right;
if (nw->right)
nw->right->parent = nw;
}
}
@ -188,7 +230,8 @@ AATREE_PREFIX struct aatree *aatree_ins(struct aatree *root,
else
break;
} else {
*old = root;
if (old)
*old = root;
aatree_replace(root, new_t);
return orig_root;
}
@ -262,7 +305,8 @@ AATREE_PREFIX struct aatree *aatree_del(struct aatree *root,
} else {
*match = root;
if (!root->right) {
repl = root->left;
assert(!root->left);
repl = NULL;
} else {
repl = root->right;
while (repl->left)
@ -321,6 +365,7 @@ AATREE_PREFIX struct aatree *aatree_del(struct aatree *root,
}
#ifdef AATREE_TEST
#include <stdio.h>
#include <stdlib.h>
#define NODE_NUM 64
typedef unsigned long (*aatree_print_fun)(struct aatree *);
@ -339,17 +384,13 @@ static void aatree_print(struct aatree *root, aatree_print_fun f)
f = def_print;
if (root->left) {
printf("%lu -> %lu;\n", f(root), f(root->left));
printf("\\\"%lu-%d\\\" -> \\\"%lu-%d\\\"; ", f(root), root->level, f(root->left), root->left->level);
aatree_print(root->left, f);
} else {
printf("%lu -> \"%lu-l\";\n", f(root), f(root));
}
if (root->right) {
printf("%lu -> %lu;\n", f(root), f(root->right));
printf("\\\"%lu-%d\\\" -> \\\"%lu-%d\\\"; ", f(root), root->level, f(root->right), root->right->level);
aatree_print(root->right, f);
} else {
printf("%lu -> \"%lu-r\";\n", f(root), f(root));
}
}
@ -420,6 +461,20 @@ static void test_multiple_insert(void)
}
}
static void test_single_delete(void)
{
struct aatree *root = NULL, *match = NULL, *old;
struct test_node test_node;
init();
root = aatree_ins(root, &nodes[0].node, &old, test_cmp);
test_node.key = 0;
assert(aatree_del(root, &test_node.node, &match, test_cmp) == NULL);
assert(match == &nodes[0].node);
}
static void test_delete(void)
{
struct aatree *root = NULL, *match = NULL, *old;
@ -445,10 +500,6 @@ static void test_delete(void)
for (i = 0; i < NODE_NUM/2; i++) {
/*
printf("digraph t%d {", i);
aatree_print(root, tnp);
printf("}\n");
fflush(stdout);
*/
test_node.key = i;
@ -461,14 +512,92 @@ static void test_delete(void)
}
}
static void shuf(int alen, int arr[])
{
int i;
int repl;
int tmp;
for (i = 0; i < alen; i++) {
tmp = arr[i];
repl = rand() % alen;
arr[i] = arr[repl];
arr[repl] = tmp;
}
}
static void test_shuffle_insert_delete(void)
{
struct aatree *root = NULL, *match = NULL, *old;
struct test_node test_node;
int i, j;
int order[NODE_NUM];
init();
for (i = 0; i < NODE_NUM; i++)
order[i] = i;
shuf(NODE_NUM, order);
for (i = 0; i < NODE_NUM; i++) {
root = aatree_ins(root, &nodes[order[i]].node, &old, test_cmp);
assert(!old);
}
for (i = 0; i < NODE_NUM; i++) {
test_node.key = i;
assert(aatree_src(root, &test_node.node, test_cmp) == &nodes[i].node);
}
shuf(NODE_NUM, order);
/*
printf("{\"t000\": \"");
aatree_print(root, tnp);
fflush(stdout);
printf("\"\n");
*/
for (i = 0; i < NODE_NUM; i++) {
test_node.key = order[i];
root = aatree_del(root, &test_node.node, &match, test_cmp);
assert(match == &nodes[order[i]].node);
/*
printf(", \"t%03d\": \"", i + 1);
aatree_print(root, tnp);
fflush(stdout);
printf("\"\n");
*/
for (j = 0; j <= i; j++) {
test_node.key = order[j];
assert(!aatree_src(root, &test_node.node, test_cmp));
}
for (j = i+1; j < NODE_NUM; j++) {
fflush(stdout);
test_node.key = order[j];
assert(aatree_src(root, &test_node.node, test_cmp) == &nodes[order[j]].node);
}
}
assert(!root);
}
int main(void)
{
test_single_insert();
test_multiple_insert();
test_single_delete();
test_delete();
test_shuffle_insert_delete();
return 0;
}
#endif /* AATREE_TEST */
#endif /* AATREE_IMPL */
#endif /* AATREE_H */