diff --git a/bintree.c b/bintree.c index 5cf82a9..1686c2b 100644 --- a/bintree.c +++ b/bintree.c @@ -1,36 +1,117 @@ #include +#include #include "stack.h" #include "bintree.h" -//TODO: binären Suchbaum implementieren -/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), - * `clearTree`: gibt den gesamten Baum frei (rekursiv), - * `treeSize`: zählt die Knoten im Baum (rekursiv), - * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ +static StackNode *iterStack = NULL; +static void pushLeftBranch(StackNode **stack, TreeNode *node); -// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates -// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). -TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) +// Inserts a new node into the BST. +// If isDuplicate == NULL → duplicates are allowed +// If isDuplicate != NULL → duplicates are ignored and *isDuplicate = 1 +TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, + CompareFctType compareFct, int *isDuplicate) { + if (root == NULL) + { + TreeNode *newNode = calloc(1, sizeof(TreeNode)); + if (!newNode) + return NULL; + newNode->data = malloc(dataSize); + if (!newNode->data) + { + free(newNode); + return NULL; + } + + memcpy(newNode->data, data, dataSize); + + if (isDuplicate) + *isDuplicate = 0; + + return newNode; + } + + int cmp = compareFct(data, root->data); + + if (cmp < 0 || (cmp == 0 && isDuplicate == NULL)) + { + root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); + } + else if (cmp > 0) + { + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + else + { + if (isDuplicate) + *isDuplicate = 1; + } + + return root; } -// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction. -// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, -// push the top node and push all its left nodes. +static void pushLeftBranch(StackNode **stack, TreeNode *node) +{ + while (node) + { + *stack = push(*stack, node); + node = node->left; + } +} + +// If root != NULL → reset iterator and start from new tree. +// If root == NULL → continue iterating. void *nextTreeData(TreeNode *root) { + // Start new iteration + if (root != NULL) + { + // reset old iterator state + clearStack(iterStack); + iterStack = NULL; + // push root and all left children + pushLeftBranch(&iterStack, root); + } + + // No active iterator + if (iterStack == NULL) + return NULL; + + // Get next node + TreeNode *node = (TreeNode *)top(iterStack); + iterStack = pop(iterStack); + + // push right subtree and its left descendants + if (node->right) + pushLeftBranch(&iterStack, node->right); + + return node->data; } -// Releases all memory resources (including data copies). +// Frees all nodes and also resets iterator. void clearTree(TreeNode *root) { + if (!root) + return; + clearTree(root->left); + clearTree(root->right); + + free(root->data); + free(root); + + // If we clear the tree, iterator must not point into freed memory. + clearStack(iterStack); + iterStack = NULL; } -// Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root) { + if (!root) + return 0; -} \ No newline at end of file + return 1 + treeSize(root->left) + treeSize(root->right); +} diff --git a/test_bintree.c b/test_bintree.c index 3ca280d..2f2ba5e 100644 --- a/test_bintree.c +++ b/test_bintree.c @@ -1,39 +1,145 @@ #include "unity.h" #include "bintree.h" -#include "string.h" +#include +#include + +static int compareInt(const void *a, const void *b) +{ + int x = *(const int *)a; + int y = *(const int *)b; + return (x > y) - (x < y); +} void setUp(void) { - // set stuff up here } void tearDown(void) { - // set stuff up here } -// this adds some strings and checks if they are returned in the right order -void test_insert_and_retrieve(void) +/* ============================================================ + TEST 1 — Strings einfügen + korrekte Reihenfolge prüfen + ============================================================ */ + +void test_insert_and_retrieve_strings(void) { char *data1 = "a_this"; char *data2 = "b_is"; char *data3 = "c_testdata"; - TreeNode *root = addToTree(NULL, data1, strlen(data1) + 1, (CompareFctType)&strcmp, NULL); - addToTree(root, data2, strlen(data2) + 1, (CompareFctType)&strcmp, NULL); - addToTree(root, data3, strlen(data3) + 1, (CompareFctType)&strcmp, NULL); + TreeNode *root = addToTree(NULL, data1, strlen(data1) + 1, (CompareFctType)strcmp, NULL); + addToTree(root, data2, strlen(data2) + 1, (CompareFctType)strcmp, NULL); + addToTree(root, data3, strlen(data3) + 1, (CompareFctType)strcmp, NULL); - TEST_ASSERT_EQUAL_STRING(data1, (char *)nextTreeData(root)); - TEST_ASSERT_EQUAL_STRING(data2, (char *)nextTreeData(NULL)); - TEST_ASSERT_EQUAL_STRING(data3, (char *)nextTreeData(NULL)); + TEST_ASSERT_EQUAL_STRING(data1, nextTreeData(root)); + TEST_ASSERT_EQUAL_STRING(data2, nextTreeData(NULL)); + TEST_ASSERT_EQUAL_STRING(data3, nextTreeData(NULL)); + TEST_ASSERT_EQUAL_PTR(NULL, nextTreeData(NULL)); // Ende clearTree(root); } +/* ============================================================ + TEST 2 — Integer einfügen + Traversierung + ============================================================ */ + +void test_insert_and_retrieve_ints(void) +{ + int a = 2, b = 1, c = 3; + + TreeNode *root = NULL; + root = addToTree(root, &a, sizeof(int), compareInt, NULL); + addToTree(root, &b, sizeof(int), compareInt, NULL); + addToTree(root, &c, sizeof(int), compareInt, NULL); + + int *v1 = nextTreeData(root); + int *v2 = nextTreeData(NULL); + int *v3 = nextTreeData(NULL); + int *v4 = nextTreeData(NULL); + + TEST_ASSERT_EQUAL_INT(1, *v1); + TEST_ASSERT_EQUAL_INT(2, *v2); + TEST_ASSERT_EQUAL_INT(3, *v3); + TEST_ASSERT_NULL(v4); + + clearTree(root); +} + +/* ============================================================ + TEST 3 — treeSize korrekt? + ============================================================ */ + +void test_tree_size(void) +{ + TreeNode *root = NULL; + + TEST_ASSERT_EQUAL_UINT(0, treeSize(root)); + + int x1 = 10, x2 = 5, x3 = 15; + root = addToTree(root, &x1, sizeof(int), compareInt, NULL); + addToTree(root, &x2, sizeof(int), compareInt, NULL); + addToTree(root, &x3, sizeof(int), compareInt, NULL); + + TEST_ASSERT_EQUAL_UINT(3, treeSize(root)); + + clearTree(root); +} + +/* ============================================================ + TEST 4 — Duplikaterkennung + ============================================================ */ + +void test_duplicate_detection(void) +{ + int x = 42; + int dupFlag = -1; + + TreeNode *root = addToTree(NULL, &x, sizeof(int), compareInt, &dupFlag); + TEST_ASSERT_EQUAL_INT(0, dupFlag); + + addToTree(root, &x, sizeof(int), compareInt, &dupFlag); + TEST_ASSERT_EQUAL_INT(1, dupFlag); + + TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); + + clearTree(root); +} + +/* ============================================================ + TEST 5 — Iterator nach clearTree → sollte NULL liefern + ============================================================ */ + +void test_iterator_after_cleartree(void) +{ + int a = 5, b = 1, c = 9; + + TreeNode *root = NULL; + root = addToTree(root, &a, sizeof(int), compareInt, NULL); + addToTree(root, &b, sizeof(int), compareInt, NULL); + addToTree(root, &c, sizeof(int), compareInt, NULL); + + nextTreeData(root); + + clearTree(root); + + TEST_ASSERT_NULL(nextTreeData(NULL)); + TEST_ASSERT_NULL(nextTreeData(NULL)); +} + int main(void) { - printf("============================\nBintree tests\n============================\n"); + printf("============================\n"); + printf("Bintree tests\n"); + printf("============================\n"); + UNITY_BEGIN(); - RUN_TEST(test_insert_and_retrieve); + + RUN_TEST(test_insert_and_retrieve_strings); + RUN_TEST(test_insert_and_retrieve_ints); + RUN_TEST(test_tree_size); + RUN_TEST(test_duplicate_detection); + RUN_TEST(test_iterator_after_cleartree); + return UNITY_END(); -} \ No newline at end of file +}