From: Michael D. Lowis Date: Sat, 27 Jun 2015 20:38:58 +0000 (-0400) Subject: Added binary search tree implementation to the data structures folder X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=cd1b7c68ae3edb29b0911cdea32533d5159904b2;p=archive%2Fcarl.git Added binary search tree implementation to the data structures folder --- diff --git a/source/data/bstree.c b/source/data/bstree.c new file mode 100644 index 0000000..2ba4eeb --- /dev/null +++ b/source/data/bstree.c @@ -0,0 +1,60 @@ +#include + +void bstree_init(bstree_t* tree, bstree_cmpfn_t cmpfn, bool allow_dups) +{ + tree->root = NULL; + tree->cmpfn = cmpfn; + tree->allow_dups = allow_dups; +} + +bool bstree_empty(bstree_t* tree) +{ + return (tree->root == NULL); +} + +static size_t subtree_size(bstree_node_t* node) +{ + if (node == NULL) + return 0; + else + return (1 + subtree_size(node->left) + subtree_size(node->right)); +} + +size_t bstree_size(bstree_t* tree) +{ + return subtree_size(tree->root); +} + +static bstree_node_t** find_node(bstree_cmpfn_t cmpfn, bstree_node_t** root, bstree_node_t* node, bool allow_dups) +{ + bstree_node_t** curr = root; + while(*curr != NULL) { + int cmp = cmpfn(node, *curr); + if (cmp < 0) + curr = &((*curr)->left); + else if (cmp > 0) + curr = &((*curr)->right); + else if (allow_dups) + curr = &((*curr)->right); + else + break; + } + return curr; +} + +void bstree_insert(bstree_t* tree, bstree_node_t* node) +{ + bstree_node_t** curr = find_node(tree->cmpfn, &(tree->root), node, tree->allow_dups); + if (*curr == NULL) { + *curr = node; + node->left = NULL; + node->right = NULL; + } +} + +bstree_node_t* bstree_lookup(bstree_t* tree, bstree_node_t* node) +{ + bstree_node_t** curr = find_node(tree->cmpfn, &(tree->root), node, false); + return *curr; +} + diff --git a/source/data/bstree.h b/source/data/bstree.h index 4beb87c..b44ac94 100644 --- a/source/data/bstree.h +++ b/source/data/bstree.h @@ -4,17 +4,22 @@ #ifndef BSTREE_H #define BSTREE_H +#include + typedef struct bstree_node_t { - struct bstree_node_t* parent; struct bstree_node_t* left; struct bstree_node_t* right; } bstree_node_t; +typedef int (*bstree_cmpfn_t)(bstree_node_t* a, bstree_node_t* b); + typedef struct { bstree_node_t* root; + bstree_cmpfn_t cmpfn; + bool allow_dups; } bstree_t; -void bstree_init(bstree_t* bstree); +void bstree_init(bstree_t* bstree, bstree_cmpfn_t cmpfn, bool allow_dups); bool bstree_empty(bstree_t* bstree); @@ -24,12 +29,4 @@ void bstree_insert(bstree_t* bstree, bstree_node_t* node); bstree_node_t* bstree_lookup(bstree_t* bstree, bstree_node_t* node); -bool bstree_node_hasnext(bstree_node_t* node); - -bstree_node_t* bstree_node_next(bstree_node_t* node); - -bool bstree_node_hasprev(bstree_node_t* node); - -bstree_node_t* bstree_node_prev(bstree_node_t* node); - #endif /* BSTREE_H */ diff --git a/tests/data/bstree.c b/tests/data/bstree.c new file mode 100644 index 0000000..f05a703 --- /dev/null +++ b/tests/data/bstree.c @@ -0,0 +1,146 @@ + +// Unit Test Framework Includes +#include "atf.h" + +// File To Test +#include + +typedef struct { + bstree_node_t node; + int val; +} int_node_t; + +int compare(bstree_node_t* a, bstree_node_t* b) +{ + int_node_t* nodea = container_of(a, int_node_t, node); + int_node_t* nodeb = container_of(b, int_node_t, node); + return (nodea->val < nodeb->val) ? -1 : (nodea->val > nodeb->val) ? 1 : 0; +} + +//----------------------------------------------------------------------------- +// Begin Unit Tests +//----------------------------------------------------------------------------- +TEST_SUITE(BSTree) { + //------------------------------------------------------------------------- + // bstree_init + //------------------------------------------------------------------------- + TEST(Verify_bstree_init_should_init_the_tree) + { + bstree_t tree; + bstree_init(&tree, NULL, true); + CHECK(tree.root == NULL); + CHECK(tree.cmpfn == NULL); + CHECK(tree.allow_dups == true); + } + + //------------------------------------------------------------------------- + // bstree_empty + //------------------------------------------------------------------------- + TEST(Verify_bstree_empty_should_return_true_if_the_tree_is_empty) + { + bstree_t tree = { 0, 0, 0 }; + CHECK(bstree_empty(&tree)); + } + + TEST(Verify_bstree_empty_should_return_false_if_the_tree_is_not_empty) + { + bstree_t tree = { (bstree_node_t*)0x1234, NULL, false }; + CHECK(!bstree_empty(&tree)); + } + + //------------------------------------------------------------------------- + // bstree_size + //------------------------------------------------------------------------- + TEST(Verify_bstree_size_should_return_0_for_empty_tree) + { + bstree_t tree = { 0, 0, 0 }; + CHECK(0 == bstree_size(&tree)); + } + + TEST(Verify_bstree_size_should_return_1) + { + bstree_node_t node1 = { NULL, NULL }; + bstree_t tree = { &node1, NULL, false }; + CHECK(1 == bstree_size(&tree)); + } + + TEST(Verify_bstree_size_should_return_2) + { + bstree_node_t node2 = { NULL, NULL }; + bstree_node_t node1 = { &node2, NULL }; + bstree_t tree = { &node1, NULL, false }; + CHECK(2 == bstree_size(&tree)); + } + + TEST(Verify_bstree_size_should_return_3) + { + bstree_node_t node3 = { NULL, NULL }; + bstree_node_t node2 = { NULL, NULL }; + bstree_node_t node1 = { &node2, &node3 }; + bstree_t tree = { &node1, NULL, false }; + CHECK(3 == bstree_size(&tree)); + } + + //------------------------------------------------------------------------- + // bstree_insert + //------------------------------------------------------------------------- + TEST(Verify_bstree_insert_should_insert_into_empty_tree) + { + int_node_t node = { {0,0}, 42 }; + bstree_t tree = { NULL, compare, false }; + bstree_insert(&tree, &(node.node)); + CHECK(tree.root = &(node.node)); + } + + TEST(Verify_bstree_insert_should_insert_to_the_left) + { + int_node_t node1 = { {0,0}, 42 }; + int_node_t node2 = { {0,0}, 41 }; + bstree_t tree = { &(node1.node), compare, false }; + bstree_insert(&tree, &(node2.node)); + CHECK(tree.root->left = &(node2.node)); + } + + TEST(Verify_bstree_insert_should_insert_to_the_right) + { + int_node_t node1 = { {0,0}, 42 }; + int_node_t node2 = { {0,0}, 43 }; + bstree_t tree = { &(node1.node), compare, false }; + bstree_insert(&tree, &(node2.node)); + CHECK(tree.root->right = &(node2.node)); + } + + //------------------------------------------------------------------------- + // bstree_lookup + //------------------------------------------------------------------------- + TEST(Verify_bstree_lookup_should_not_find_the_item_in_an_empty_tree) + { + int_node_t node1 = { {0,0}, 42 }; + bstree_t tree = { NULL, compare, false }; + CHECK(bstree_lookup(&tree, &(node1.node)) == NULL); + } + + TEST(Verify_bstree_lookup_should_find_the_item_at_the_root) + { + int_node_t node1 = { {0,0}, 42 }; + bstree_t tree = { &(node1.node), compare, false }; + CHECK(bstree_lookup(&tree, &(node1.node)) == &(node1.node)); + } + + TEST(Verify_bstree_lookup_should_find_the_item_to_the_left) + { + int_node_t node2 = { {0,0}, 41 }; + int_node_t node1 = { {&(node2.node),0}, 42 }; + bstree_t tree = { &(node1.node), compare, false }; + CHECK(bstree_lookup(&tree, &(node2.node)) == &(node2.node)); + } + + TEST(Verify_bstree_lookup_should_find_the_item_to_the_right) + { + int_node_t node2 = { {0,0}, 43 }; + int_node_t node1 = { {0,&(node2.node)}, 42 }; + bstree_t tree = { &(node1.node), compare, false }; + CHECK(bstree_lookup(&tree, &(node2.node)) == &(node2.node)); + } + +} diff --git a/tests/main.c b/tests/main.c index 11ce75b..a6ef543 100644 --- a/tests/main.c +++ b/tests/main.c @@ -7,5 +7,6 @@ void main(int argc, char** argv) (void)argv; RUN_EXTERN_TEST_SUITE(RefCount); RUN_EXTERN_TEST_SUITE(SList); + RUN_EXTERN_TEST_SUITE(BSTree); exit(PRINT_TEST_RESULTS()); }