feat(tree): add tree iterator
parent
ef5037f941
commit
a6ed89d8cd
|
@ -9,7 +9,8 @@ typedef struct vieter_tree vieter_tree;
|
||||||
typedef enum vieter_tree_error {
|
typedef enum vieter_tree_error {
|
||||||
vieter_tree_ok = 0,
|
vieter_tree_ok = 0,
|
||||||
vieter_tree_already_present = 1,
|
vieter_tree_already_present = 1,
|
||||||
vieter_tree_not_present = 2
|
vieter_tree_not_present = 2,
|
||||||
|
vieter_tree_iterator_done = 3
|
||||||
} vieter_tree_error;
|
} 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);
|
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
|
#endif
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
#include "vieter_tree_internal.h"
|
|
||||||
#include "vieter_tree_node.h"
|
|
||||||
#include "vieter_tree_balancing.h"
|
#include "vieter_tree_balancing.h"
|
||||||
|
#include "vieter_tree_internal.h"
|
||||||
struct vieter_tree {
|
|
||||||
uint64_t size;
|
|
||||||
vieter_tree_node *root;
|
|
||||||
};
|
|
||||||
|
|
||||||
vieter_tree *vieter_tree_init() { return calloc(1, sizeof(vieter_tree)); }
|
vieter_tree *vieter_tree_init() { return calloc(1, sizeof(vieter_tree)); }
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,22 @@
|
||||||
#include "vieter_tree.h"
|
#include "vieter_tree.h"
|
||||||
|
#include "vieter_tree_node.h"
|
||||||
|
|
||||||
#include <stdbool.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.
|
* Inspect whether the tree is still a valid red-black-tree.
|
||||||
*
|
*
|
||||||
* @return true if valid, false otherwise.
|
* @return true if valid, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool vieter_tree_validate(vieter_tree *tree);
|
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) {
|
bool vieter_tree_node_get(vieter_tree_node *node, vieter_tree_node_flag flag) {
|
||||||
return (node->flags & flag) != 0;
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -16,19 +16,30 @@ void test_insert() {
|
||||||
vieter_tree *tree = vieter_tree_init();
|
vieter_tree *tree = vieter_tree_init();
|
||||||
|
|
||||||
for (uint64_t i = 0; i < 250; i++) {
|
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_SIZE(tree, i + 1);
|
||||||
TEST_CHECK(vieter_tree_validate(tree));
|
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++) {
|
for (uint64_t i = 0; i < 250; i++) {
|
||||||
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok);
|
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_insert(tree, i, NULL) == vieter_tree_already_present);
|
||||||
TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok);
|
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);
|
vieter_tree_free(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue