forked from vieter-v/libvieter
feat(tree): add tree iterator
parent
ef5037f941
commit
a6ed89d8cd
|
@ -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
|
||||
|
|
|
@ -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)); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue