#include #include #include "stack.h" #include "bintree.h" /* Schiebt einen Knoten und alle seine linken Nachfolger (entlang der "linken Kante") auf den Iterator-Stack. iterStackPtr: Zeiger auf den Top-Zeiger des Stacks (LIFO) für die Wiederholung knoten: aktueller Startknoten, dessen linke Kette abgelegt wird */ static void bintree_pushLefts(StackNode **iterStackPtr, TreeNode *knoten) { while (knoten != NULL) { *iterStackPtr = push(*iterStackPtr, knoten); // aktuellen Knoten oben auf den Stack legen knoten = knoten->left; // zum linken Kind weiterlaufen } } /* Fügt eine Kopie der Daten (Speicherbereich von 'data' mit Länge 'dataSize') in den Baum ein. Die Ordnung wird über 'compareFct' festgelegt. Duplikate: - Wenn 'isDuplicate' != NULL übergeben wird: Duplikate werden NICHT eingefügt, stattdessen wird *isDuplicate = 1 gesetzt (bei neuem Eintrag = 0). - Wenn 'isDuplicate' == NULL: Duplikate SIND erlaubt; der Duplikat-Eintrag wird in den rechten Teilbaum eingefügt. Rückgabe: - Zeiger auf die (ggf. unveränderte oder neue) Wurzel des Teilbaums. - NULL bei Speicherfehlern beim Anlegen des ersten Knotens. */ TreeNode *addToTree(TreeNode *wurzel, const void *daten, size_t datenGroesse, CompareFctType vergleichFkt, int *istDuplikat) { // Standardmäßig annehmen: kein Duplikat (falls Ausgabefeld vorhanden) if (istDuplikat != NULL) *istDuplikat = 0; // Leerer Baum/Teilbaum: neuen Knoten erzeugen if (wurzel == NULL) { TreeNode *neuerKnoten = (TreeNode *)malloc(sizeof(TreeNode)); if (neuerKnoten == NULL) return NULL; // Speicherfehler neuerKnoten->data = malloc(datenGroesse); if (neuerKnoten->data == NULL) { free(neuerKnoten); return NULL; // Speicherfehler für Datenbereich } memcpy(neuerKnoten->data, daten, datenGroesse); // tiefe Kopie der Nutzdaten neuerKnoten->left = neuerKnoten->right = NULL; // Blatt return neuerKnoten; } // Vergleich der einzufügenden Daten mit dem aktuellen Knoten int vergleich = vergleichFkt(daten, wurzel->data); if (vergleich < 0) { // links einfügen wurzel->left = addToTree(wurzel->left, daten, datenGroesse, vergleichFkt, istDuplikat); } else if (vergleich > 0) { // rechts einfügen wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat); } else { // Gleichheit (potenzielles Duplikat) if (istDuplikat != NULL) { *istDuplikat = 1; // Duplikat erkannt, NICHT einfügen // keine Änderung am Baum } else { // Duplikate erlaubt -> konventionell in den rechten Teilbaum einfügen wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat); } } return wurzel; } /* Die Funktion gibt bei jedem Aufruf das nächste Element des Binärbaums in **Inorder-Reihenfolge** zurück und merkt sich intern, wo sie zuletzt war. */ void *nextTreeData(TreeNode *wurzel) { static StackNode *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg // Neuer Baum übergeben -> Iterator zurücksetzen/initialisieren if (wurzel != NULL) { clearStack(iteratorStack); // ggf. alten Stack leeren (Speicher freigeben) iteratorStack = NULL; // Top-Zeiger zurücksetzen bintree_pushLefts(&iteratorStack, wurzel); // Wurzel und linke Kette ablegen } // Kein weiterer Eintrag? if (iteratorStack == NULL) return NULL; // Nächsten Knoten holen (oberstes Stack-Element) TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack); //Oberstes Element zurück iteratorStack = pop(iteratorStack); // entfernt Oberstes Element // Falls rechter Teilbaum existiert: dessen linke Kette ablegen if (aktuellerKnoten->right != NULL) bintree_pushLefts(&iteratorStack, aktuellerKnoten->right); // Daten des aktuellen Knotens zurückgeben return aktuellerKnoten->data; } /* Gibt den gesamten Baum frei (inkl. der tief kopierten Daten). */ void clearTree(TreeNode *wurzel) { if (wurzel == NULL) return; clearTree(wurzel->left); clearTree(wurzel->right); free(wurzel->data); free(wurzel); } /* Liefert die Anzahl der Knoten/Einträge im Teilbaum 'wurzel'. */ unsigned int treeSize(const TreeNode *wurzel) { if (wurzel == NULL) return 0; return 1U + treeSize(wurzel->left) + treeSize(wurzel->right); }