#include #include "stack.h" #include "bintree.h" // Fügt ein neues Element in den Binärbaum ein. // - data wird kopiert (tiefe Kopie) // - compareFct bestimmt die Sortierreihenfolge // - Duplikate sind erlaubt, außer isDuplicate ist gesetzt TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { // Ungültige Parameter → Baum unverändert zurückgeben if (data == NULL || compareFct == NULL) return root; // Fall: leerer Teilbaum → neuer Knoten wird erzeugt if (root == NULL) { // Speicher für neuen Baumknoten reservieren TreeNode *node = malloc(sizeof(TreeNode)); if (node == NULL) return NULL; // Speicher für die Nutzdaten reservieren node->data = malloc(dataSize); if (node->data == NULL) { free(node); return NULL; } // Daten in den Knoten kopieren memcpy(node->data, data, dataSize); // Linke und rechte Kindzeiger initialisieren node->left = NULL; node->right = NULL; // Kein Duplikat, da neuer Knoten if (isDuplicate != NULL) *isDuplicate = 0; return node; } // Vergleich der neuen Daten mit den Daten im aktuellen Knoten int cmp = compareFct(data, root->data); if (cmp < 0) { // Neuer Wert ist kleiner → Rekursion im linken Teilbaum root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); } else if (cmp > 0) { // Neuer Wert ist größer → Rekursion im rechten Teilbaum root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } else { // Gleicher Wert → Duplikat if (isDuplicate != NULL) { // Duplikat melden, aber nicht einfügen *isDuplicate = 1; } else { // Duplikate sind erlaubt → z.B. links einfügen root->left = addToTree(root->left, data, dataSize, compareFct, NULL); } } // Wurzel des (Teil-)Baumes zurückgeben return root; } // Globaler interner Stack für die Baum-Traversierung // Ermöglicht ein strtok-ähnliches Iterator-Verhalten static StackNode *iterStack = NULL; // Hilfsfunktion: // Legt den Startknoten und alle seine linken Nachfolger auf den Stack static void pushLeftPath(TreeNode *start) { // Solange noch ein Knoten existiert while (start != NULL) { // Aktuellen Knoten auf den Stack legen iterStack = push(iterStack, start); // Zum linken Kind weitergehen start = start->left; } } // Gibt nacheinander die Daten des Baumes in sortierter Reihenfolge zurück. // - Beim ersten Aufruf root ≠ NULL → neue Traversierung // - Danach root == NULL → nächstes Element liefern void *nextTreeData(TreeNode *root) { if (root != NULL) { // Neue Traversierung starten → alten Stack leeren if (iterStack != NULL) { clearStack(iterStack); iterStack = NULL; } // Wurzel und alle linken Knoten auf den Stack legen pushLeftPath(root); } // Kein weiteres Element vorhanden if (iterStack == NULL) return NULL; // Oberstes Stack-Element holen (nächster Baumknoten) TreeNode *node = (TreeNode *)top(iterStack); iterStack = pop(iterStack); // Rechten Teilbaum dieses Knotens behandeln // → dessen linker Pfad wird auf den Stack gelegt if (node->right != NULL) pushLeftPath(node->right); // Daten des aktuellen Knotens zurückgeben return node->data; } // Gibt den gesamten Speicher des Baumes frei (inkl. gespeicherter Daten) void clearTree(TreeNode *root) { // Abbruchbedingung der Rekursion if (root == NULL) return; // Zuerst linken Teilbaum freigeben clearTree(root->left); // Dann rechten Teilbaum freigeben clearTree(root->right); // Danach Daten und Knoten selbst freigeben free(root->data); free(root); } // Liefert die Anzahl aller Knoten im Baum unsigned int treeSize(const TreeNode *root) { // Leerer Baum hat Größe 0 if (root == NULL) return 0; // 1 (aktueller Knoten) + Größe linker + Größe rechter Teilbaum return 1u + treeSize(root->left) + treeSize(root->right); }