160 lines
4.3 KiB
C
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);
|
|
}
|