Kommentare hinzugefügt

This commit is contained in:
muellermo100295 2025-12-10 22:43:39 +01:00
parent 0d8a303742
commit 23dccdfd8d
2 changed files with 163 additions and 72 deletions

177
bintree.c
View File

@ -1,111 +1,148 @@
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "bintree.h"
// internal helper to push node and all its left descendants onto iterator stack
static void bintree_pushLefts(StackNode **iterStackPtr, TreeNode *n)
/*
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(n != NULL)
while (knoten != NULL)
{
*iterStackPtr = push(*iterStackPtr, n);
n = n->left;
*iterStackPtr = push(*iterStackPtr, knoten); // aktuellen Knoten oben auf den Stack legen
knoten = knoten->left; // zum linken Kind weiterlaufen
}
}
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
if(isDuplicate != NULL)
*isDuplicate = 0;
/*
Fügt eine Kopie der Daten (Speicherbereich von 'data' mit Länge 'dataSize') in den Baum ein.
Die Ordnung wird über 'compareFct' festgelegt.
if(root == NULL)
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)
{
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
if(node == NULL)
return NULL;
node->data = malloc(dataSize);
if(node->data == NULL)
// Standardmäßig annehmen: kein Duplikat (falls Ausgabefeld vorhanden)
if (istDuplikat != NULL)
*istDuplikat = 0;
// Leerer Baum/Teilbaum: neuen Knoten erzeugen
if (wurzel == NULL)
{
free(node);
return NULL;
}
memcpy(node->data, data, dataSize);
node->left = node->right = NULL;
return node;
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
}
int cmp = compareFct(data, root->data);
if(cmp < 0)
{
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
memcpy(neuerKnoten->data, daten, datenGroesse); // tiefe Kopie der Nutzdaten
neuerKnoten->left = neuerKnoten->right = NULL; // Blatt
return neuerKnoten;
}
else if(cmp > 0)
// Vergleich der einzufügenden Daten mit dem aktuellen Knoten
int vergleich = vergleichFkt(daten, wurzel->data);
if (vergleich < 0)
{
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
// links einfügen
wurzel->left = addToTree(wurzel->left, daten, datenGroesse, vergleichFkt, istDuplikat);
}
else // equal
else if (vergleich > 0)
{
if(isDuplicate != NULL)
{
*isDuplicate = 1;
// do not insert duplicate
// rechts einfügen
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
}
else
{
// duplicates allowed -> insert into right subtree
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
}
return root;
}
// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction.
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element,
// push the top node and push all its left nodes.
void *nextTreeData(TreeNode *root)
// Gleichheit (potenzielles Duplikat)
if (istDuplikat != NULL)
{
static StackNode *iterStack = NULL;
// If a new tree root is provided -> reset iterator
if(root != NULL)
*istDuplikat = 1; // Duplikat erkannt, NICHT einfügen
// keine Änderung am Baum
}
else
{
clearStack(iterStack);
iterStack = NULL;
bintree_pushLefts(&iterStack, root);
// Duplikate erlaubt -> konventionell in den rechten Teilbaum einfügen
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
}
}
if(iterStack == NULL)
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;
TreeNode *node = (TreeNode *)top(iterStack);
iterStack = pop(iterStack);
// Nächsten Knoten holen (oberstes Stack-Element)
TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack);
iteratorStack = pop(iteratorStack);
if(node->right != NULL)
bintree_pushLefts(&iterStack, node->right);
// Falls rechter Teilbaum existiert: dessen linke Kette ablegen
if (aktuellerKnoten->right != NULL)
bintree_pushLefts(&iteratorStack, aktuellerKnoten->right);
return node->data;
// Daten des aktuellen Knotens zurückgeben
return aktuellerKnoten->data;
}
// Releases all memory resources (including data copies).
void clearTree(TreeNode *root)
/*
Gibt den gesamten Baum frei (inkl. der tief kopierten Daten).
*/
void clearTree(TreeNode *wurzel)
{
if(root == NULL)
if (wurzel == NULL)
return;
clearTree(root->left);
clearTree(root->right);
clearTree(wurzel->left);
clearTree(wurzel->right);
free(root->data);
free(root);
free(wurzel->data);
free(wurzel);
}
// Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root)
/*
Liefert die Anzahl der Knoten/Einträge im Teilbaum 'wurzel'.
*/
unsigned int treeSize(const TreeNode *wurzel)
{
if(root == NULL)
if (wurzel == NULL)
return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
return 1U + treeSize(wurzel->left) + treeSize(wurzel->right);
}

View File

@ -1,27 +1,81 @@
#ifndef BINTREE_H
#define BINTREE_H
#include <stdlib.h>
/*
Typdefinition für die Vergleichsfunktion.
Die Funktion muss zwei Datenzeiger vergleichen und zurückgeben:
- < 0, wenn arg1 kleiner als arg2 ist
- 0, wenn arg1 gleich arg2 ist
- > 0, wenn arg1 größer als arg2 ist
*/
typedef int (*CompareFctType)(const void *arg1, const void *arg2);
/*
Struktur für einen Binärbaum-Knoten.
Enthält:
- data: Zeiger auf die gespeicherten Daten (beliebiger Typ, dynamisch allokiert)
- left: Zeiger auf linken Teilbaum
- right: Zeiger auf rechten Teilbaum
*/
typedef struct node
{
void *data;
struct node *left;
struct node *right;
void *data; // Zeiger auf die Nutzdaten
struct node *left; // Zeiger auf linken Kindknoten
struct node *right; // Zeiger auf rechten Kindknoten
} TreeNode;
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
/*
Fügt eine Kopie der Daten in den Binärbaum ein.
Parameter:
root : Wurzel des (Teil-)Baums
data : Zeiger auf die einzufügenden Daten
dataSize : Größe der Daten in Bytes
compareFct : Vergleichsfunktion für die Ordnung
isDuplicate : Optionaler Zeiger:
- Wenn NULL: Duplikate sind erlaubt
- Wenn != NULL: Duplikate werden ignoriert und *isDuplicate wird gesetzt:
- 0: neuer Eintrag eingefügt
- 1: Duplikat erkannt, nicht eingefügt
Rückgabe:
Zeiger auf die (ggf. neue) Wurzel des Baums oder NULL bei Speicherfehler.
*/
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate);
// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction.
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element,
// push the top node and push all its left nodes.
/*
Iteriert über den Baum in Inorder-Reihenfolge.
Verhalten:
- Erster Aufruf mit root != NULL: Iterator initialisieren
- Folgeaufrufe mit root == NULL: nächstes Element zurückgeben
Rückgabe:
Zeiger auf die Daten des nächsten Knotens oder NULL, wenn Ende erreicht.
Hinweis:
Intern wird ein Stack verwendet. Nicht threadsicher.
*/
void *nextTreeData(TreeNode *root);
// Releases all memory resources (including data copies).
/*
Gibt den gesamten Baum frei (inklusive der gespeicherten Daten).
Nach dem Aufruf sind alle Zeiger ungültig.
*/
void clearTree(TreeNode *root);
// Returns the number of entries in the tree given by root.
/*
Liefert die Anzahl der Knoten im Baum.
Rückgabe:
Anzahl der Knoten (0 bei leerem Baum).
*/
unsigned int treeSize(const TreeNode *root);
#endif