149 lines
4.5 KiB
C
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);
|
|
}
|