feat(tree): add tree iterator

red-black-tree
Jef Roosens 2023-02-02 14:10:35 +01:00
parent ef5037f941
commit a6ed89d8cd
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
7 changed files with 123 additions and 10 deletions

View File

@ -9,7 +9,8 @@ typedef struct vieter_tree vieter_tree;
typedef enum vieter_tree_error {
vieter_tree_ok = 0,
vieter_tree_already_present = 1,
vieter_tree_not_present = 2
vieter_tree_not_present = 2,
vieter_tree_iterator_done = 3
} vieter_tree_error;
/*
@ -45,4 +46,25 @@ vieter_tree_error vieter_tree_remove(void **out, vieter_tree *tree,
*/
uint64_t vieter_tree_size(vieter_tree *tree);
/*
* An iterator that can be used to traverse a tree in-order.
*/
typedef struct vieter_tree_iterator vieter_tree_iterator;
/*
* Allocate and initialize a new iterator from the given tree.
*/
vieter_tree_iterator *vieter_tree_iterator_from(vieter_tree *tree);
/*
* Free an iterator.
*/
void vieter_tree_iterator_free(vieter_tree_iterator **ptp);
/*
* Return the iterator's next element.
*/
vieter_tree_error vieter_tree_iterator_next(void **out,
vieter_tree_iterator *iter);
#endif

View File

@ -1,11 +1,5 @@
#include "vieter_tree_internal.h"
#include "vieter_tree_node.h"
#include "vieter_tree_balancing.h"
struct vieter_tree {
uint64_t size;
vieter_tree_node *root;
};
#include "vieter_tree_internal.h"
vieter_tree *vieter_tree_init() { return calloc(1, sizeof(vieter_tree)); }

View File

@ -1,10 +1,22 @@
#include "vieter_tree.h"
#include "vieter_tree_node.h"
#include <stdbool.h>
struct vieter_tree {
uint64_t size;
vieter_tree_node *root;
};
/*
* Inspect whether the tree is still a valid red-black-tree.
*
* @return true if valid, false otherwise.
*/
bool vieter_tree_validate(vieter_tree *tree);
struct vieter_tree_iterator {
vieter_tree_node *current_node;
bool started;
bool done;
};

View File

@ -0,0 +1,49 @@
#include "vieter_tree.h"
#include "vieter_tree_internal.h"
vieter_tree_iterator *vieter_tree_iterator_from(vieter_tree *tree) {
vieter_tree_iterator *iter = calloc(1, sizeof(vieter_tree_iterator));
// An empty tree's iterator will be done immediately
if (tree->size == 0) {
iter->started = true;
iter->done = true;
return iter;
}
iter->current_node = tree->root;
return iter;
}
vieter_tree_error vieter_tree_iterator_next(void **out,
vieter_tree_iterator *iter) {
if (iter->done) {
return vieter_tree_iterator_done;
}
if (!iter->started) {
while (iter->current_node->children[0] != NULL) {
iter->current_node = iter->current_node->children[0];
}
iter->started = true;
}
*out = iter->current_node->data;
iter->current_node = vieter_tree_node_next(iter->current_node);
if (iter->current_node == NULL) {
iter->done = true;
}
return vieter_tree_ok;
}
void vieter_tree_iterator_free(vieter_tree_iterator **ptp) {
free(*ptp);
*ptp = NULL;
}

View File

@ -150,3 +150,22 @@ void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag,
bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag) {
return (node->flags & flag) != 0;
}
vieter_tree_node *vieter_tree_node_next(vieter_tree_node *node) {
if (node->children[1] != NULL) {
node = node->children[1];
while (node->children[0] != NULL) {
node = node->children[0];
}
return node;
}
while (node->parent != NULL &&
vieter_tree_node_get(node, vieter_tree_node_right)) {
node = node->parent;
}
return node->parent;
}

View File

@ -77,4 +77,10 @@ void vieter_tree_node_set_children(vieter_tree_node *parent, vieter_tree_node **
*/
void vieter_tree_node_set_child(vieter_tree_node *parent, vieter_tree_node *child, bool right);
/*
* Return the in-order successor of the given node, or NULL if it's the last
* node in the tree.
*/
vieter_tree_node *vieter_tree_node_next(vieter_tree_node *node);
#endif

View File

@ -16,19 +16,30 @@ void test_insert() {
vieter_tree *tree = vieter_tree_init();
for (uint64_t i = 0; i < 250; i++) {
TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok);
TEST_CHECK(vieter_tree_insert(tree, i, (void *)i) == vieter_tree_ok);
TEST_SIZE(tree, i + 1);
TEST_CHECK(vieter_tree_validate(tree));
}
void *out;
vieter_tree_iterator *iter = vieter_tree_iterator_from(tree);
void *out = NULL;
for (uint64_t i = 0; i < 250; i++) {
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok);
TEST_CHECK(out == (void *)i);
TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_already_present);
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok);
out = NULL;
TEST_CHECK(vieter_tree_iterator_next(&out, iter) == vieter_tree_ok);
TEST_CHECK(out == (void *)i);
}
TEST_CHECK(vieter_tree_iterator_next(&out, iter) == vieter_tree_iterator_done);
vieter_tree_iterator_free(&iter);
vieter_tree_free(tree);
}