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); +}