fix bug where replaced nodes did not have the same level
This commit is contained in:
parent
91640931d9
commit
ffc9602661
|
@ -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.
|
systems.
|
||||||
|
|
||||||
The implementation is about 300 lines.
|
The implementation is about 300 lines.
|
||||||
|
@ -38,7 +38,9 @@ own structure and search function like ::
|
||||||
return strcmp(n1->key, n2->key);
|
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
|
Using the Library
|
||||||
|
|
157
aatree.h
157
aatree.h
|
@ -36,22 +36,56 @@ struct aatree {
|
||||||
unsigned level;
|
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 *);
|
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,
|
AATREE_PREFIX struct aatree *aatree_ins(struct aatree *root,
|
||||||
struct aatree *new_t,
|
struct aatree *new_t,
|
||||||
struct aatree **old,
|
struct aatree **old,
|
||||||
aatree_cmp_f cmp);
|
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,
|
AATREE_PREFIX struct aatree *aatree_src(struct aatree *root,
|
||||||
struct aatree *key,
|
struct aatree *key,
|
||||||
aatree_cmp_f cmp);
|
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,
|
AATREE_PREFIX static struct aatree *aatree_del(struct aatree *root,
|
||||||
struct aatree *key,
|
struct aatree *key,
|
||||||
struct aatree **match,
|
struct aatree **match,
|
||||||
aatree_cmp_f cmp);
|
aatree_cmp_f cmp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a node.
|
||||||
|
*/
|
||||||
static void aatree_init(struct aatree *t)
|
static void aatree_init(struct aatree *t)
|
||||||
{
|
{
|
||||||
t->left = t->right = t->parent = NULL;
|
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);
|
aatree_relink(old, nw);
|
||||||
if (nw) {
|
if (nw) {
|
||||||
nw->left = old->left;
|
nw->level = old->level;
|
||||||
nw->right = old->right;
|
|
||||||
nw->parent = old->parent;
|
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
|
else
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
*old = root;
|
if (old)
|
||||||
|
*old = root;
|
||||||
aatree_replace(root, new_t);
|
aatree_replace(root, new_t);
|
||||||
return orig_root;
|
return orig_root;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +305,8 @@ AATREE_PREFIX struct aatree *aatree_del(struct aatree *root,
|
||||||
} else {
|
} else {
|
||||||
*match = root;
|
*match = root;
|
||||||
if (!root->right) {
|
if (!root->right) {
|
||||||
repl = root->left;
|
assert(!root->left);
|
||||||
|
repl = NULL;
|
||||||
} else {
|
} else {
|
||||||
repl = root->right;
|
repl = root->right;
|
||||||
while (repl->left)
|
while (repl->left)
|
||||||
|
@ -321,6 +365,7 @@ AATREE_PREFIX struct aatree *aatree_del(struct aatree *root,
|
||||||
}
|
}
|
||||||
#ifdef AATREE_TEST
|
#ifdef AATREE_TEST
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#define NODE_NUM 64
|
#define NODE_NUM 64
|
||||||
|
|
||||||
typedef unsigned long (*aatree_print_fun)(struct aatree *);
|
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;
|
f = def_print;
|
||||||
|
|
||||||
if (root->left) {
|
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);
|
aatree_print(root->left, f);
|
||||||
} else {
|
|
||||||
printf("%lu -> \"%lu-l\";\n", f(root), f(root));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root->right) {
|
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);
|
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)
|
static void test_delete(void)
|
||||||
{
|
{
|
||||||
struct aatree *root = NULL, *match = NULL, *old;
|
struct aatree *root = NULL, *match = NULL, *old;
|
||||||
|
@ -445,10 +500,6 @@ static void test_delete(void)
|
||||||
|
|
||||||
for (i = 0; i < NODE_NUM/2; i++) {
|
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;
|
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)
|
int main(void)
|
||||||
{
|
{
|
||||||
test_single_insert();
|
test_single_insert();
|
||||||
test_multiple_insert();
|
test_multiple_insert();
|
||||||
|
test_single_delete();
|
||||||
test_delete();
|
test_delete();
|
||||||
|
test_shuffle_insert_delete();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* AATREE_TEST */
|
#endif /* AATREE_TEST */
|
||||||
#endif /* AATREE_IMPL */
|
#endif /* AATREE_IMPL */
|
||||||
#endif /* AATREE_H */
|
#endif /* AATREE_H */
|
||||||
|
|
Loading…
Reference in New Issue