#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. */ // 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). // Hilfsfunktion: neuen Knoten erstellen und Daten kopieren static TreeNode* createNode(const void* data, size_t dataSize) { TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); if (node == NULL) { return NULL; } node->data = malloc(dataSize); if (node->data == NULL) { free(node); return NULL; } memcpy(node->data, data, dataSize); // dataSize wird NICHT im struct gespeichert, da es nicht im Header ist node->left = NULL; node->right = NULL; return node; } // Fügt eine Kopie der Daten in den Baum ein (rekursiv) TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { // Basisfall: leerer Baum oder Blattknoten erreicht if (root == NULL) { // isDuplicate auf 0 setzen, wenn nicht NULL if (isDuplicate != NULL) { *isDuplicate = 0; } return createNode(data, dataSize); } // Daten vergleichen int result = compareFct(data, root->data); if (result < 0) { // Daten sind kleiner -> in linken Teilbaum einfügen root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); } else if (result > 0) { // Daten sind größer -> in rechten Teilbaum einfügen root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } else { // result == 0 → Duplikat gefunden if (isDuplicate != NULL) { *isDuplicate = 1; // Duplikat, nicht einfügen } else { // Duplikate sind erlaubt -> in rechten Teilbaum einfügen root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } } return root; } // Statischer Stack für die Iterator-Funktion (wie bei strtok) static StackNode *iteratorStack = NULL; // Iteriert über den Baum (In-Order-Traversierung mit Stack) // Funktioniert wie strtok: beim ersten Aufruf root übergeben, dann NULL void *nextTreeData(TreeNode *root) { // Wenn root != NULL: neuer Iterator-Durchlauf starten if (root != NULL) { // Alten Stack löschen, falls vorhanden clearStack(iteratorStack); iteratorStack = NULL; // Alle linken Knoten auf den Stack pushen (bis zum kleinsten Element) TreeNode *current = root; while (current != NULL) { iteratorStack = push(iteratorStack, current); current = current->left; } } // Wenn Stack leer ist, sind wir fertig if (iteratorStack == NULL) { return NULL; } // Oberstes Element vom Stack holen TreeNode *node = (TreeNode *)top(iteratorStack); iteratorStack = pop(iteratorStack); // Wenn der Knoten einen rechten Teilbaum hat, // alle linken Knoten des rechten Teilbaums auf den Stack pushen if (node->right != NULL) { TreeNode *current = node->right; while (current != NULL) { iteratorStack = push(iteratorStack, current); current = current->left; } } // Daten des aktuellen Knotens zurückgeben return node->data; } // Gibt den gesamten Baum frei (rekursiv, Post-Order) void clearTree(TreeNode *root) { if (root == NULL) { return; // Basisfall: leerer Teilbaum } // Erst linken Teilbaum löschen clearTree(root->left); // Dann rechten Teilbaum löschen clearTree(root->right); // Dann Daten und Knoten selbst löschen free(root->data); // Knoten selbst freigeben free(root); } // Zählt die Knoten im Baum (rekursiv) unsigned int treeSize(const TreeNode *root) { if (root == NULL) { return 0; // Basisfall: leerer Teilbaum } // Rekursiv: Größe = 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum return 1 + treeSize(root->left) + treeSize(root->right); }