Team5_Doble/bintree.c
2025-12-10 22:43:39 +01:00

149 lines
4.5 KiB
C

#include <stdlib.h>
#include <string.h>
#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;
}
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);
iteratorStack = pop(iteratorStack);
// 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);
}