2025-12-15 21:04:35 +01:00

160 lines
4.3 KiB
C

#include <string.h>
#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);
}