#include #include "stack.h" #include "bintree.h" #include // 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. */ // 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) { TreeNode *insertedNode; // create a new node if the current node is NULL if (root == NULL) { // it's important to zero the pointers for adjacent nodes insertedNode = calloc(1, sizeof(TreeNode)); if (!insertedNode) { return NULL; } insertedNode->data = malloc(dataSize); if (!insertedNode->data) { return NULL; } memcpy(insertedNode->data, data, dataSize); // reset isDuplicate if it exists if (isDuplicate) { *isDuplicate = 0; } return insertedNode; } // TODO: what is the correct data type here? int cmpRes = (*compareFct)(data, root->data); // insert into the left branch if (cmpRes < 0 || (cmpRes == 0 && isDuplicate == NULL)) { root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); } // insert into the right branch else if (cmpRes > 0) { root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } // the data is equal to the current node else { // the data already exists in the tree and duplicates are ignored (isDuplicate* not NULL) *isDuplicate = 1; } return root; } // push all left descendants from @param node static void pushLeftDesc(StackNode **stackPtr, TreeNode *node) { if (!stackPtr || !node) { return; } TreeNode *curNode = node; while (curNode->left) { *stackPtr = push(*stackPtr, curNode->left); if (!*stackPtr) { return; } curNode = curNode->left; } } // 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. void *nextTreeData(TreeNode *root) { // this creates a static variable that maintains an internal state static StackNode *stack; // create a new stack if (root) { // clear possibly existing stacks clearStack(stack); // init a new stack stack = push(NULL, root); // init failed if (!stack) { return NULL; } pushLeftDesc(&stack, root); // return the first val return nextTreeData(NULL); } // neither stack nor root exist if (!stack) { return NULL; } // get next val with stack TreeNode *res = top(stack); stack = pop(stack); if (res->right) { stack = push(stack, res->right); pushLeftDesc(&stack, res->right); } return res->data; } // Releases all memory resources (including data copies). void clearTree(TreeNode *root) { // this check is crucial for recursion if (!root) { // nothing to clear return; } // release the resources of child nodes first clearTree(root->left); clearTree(root->right); // free the data (it's just a copy created in addToTree()) free(root->data); free(root); } // Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root) { // there are no nodes if (!root) { return 0; } return 1 + treeSize(root->left) + treeSize(root->right); }