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

159
bintree.c
View File

@ -1,111 +1,148 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "stack.h" #include "stack.h"
#include "bintree.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); *iterStackPtr = push(*iterStackPtr, knoten); // aktuellen Knoten oben auf den Stack legen
n = n->left; 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). Fügt eine Kopie der Daten (Speicherbereich von 'data' mit Länge 'dataSize') in den Baum ein.
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) 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)
{ {
if(isDuplicate != NULL) // Standardmäßig annehmen: kein Duplikat (falls Ausgabefeld vorhanden)
*isDuplicate = 0; if (istDuplikat != NULL)
*istDuplikat = 0;
if(root == NULL) // Leerer Baum/Teilbaum: neuen Knoten erzeugen
if (wurzel == NULL)
{ {
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode)); TreeNode *neuerKnoten = (TreeNode *)malloc(sizeof(TreeNode));
if(node == NULL) if (neuerKnoten == NULL)
return NULL; return NULL; // Speicherfehler
node->data = malloc(dataSize);
if(node->data == NULL) neuerKnoten->data = malloc(datenGroesse);
if (neuerKnoten->data == NULL)
{ {
free(node); free(neuerKnoten);
return NULL; return NULL; // Speicherfehler für Datenbereich
} }
memcpy(node->data, data, dataSize);
node->left = node->right = NULL; memcpy(neuerKnoten->data, daten, datenGroesse); // tiefe Kopie der Nutzdaten
return node; neuerKnoten->left = neuerKnoten->right = NULL; // Blatt
return neuerKnoten;
} }
int cmp = compareFct(data, root->data); // Vergleich der einzufügenden Daten mit dem aktuellen Knoten
if(cmp < 0) int vergleich = vergleichFkt(daten, wurzel->data);
if (vergleich < 0)
{ {
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); // links einfügen
wurzel->left = addToTree(wurzel->left, daten, datenGroesse, vergleichFkt, istDuplikat);
} }
else if(cmp > 0) else if (vergleich > 0)
{ {
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); // rechts einfügen
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
} }
else // equal else
{ {
if(isDuplicate != NULL) // Gleichheit (potenzielles Duplikat)
if (istDuplikat != NULL)
{ {
*isDuplicate = 1; *istDuplikat = 1; // Duplikat erkannt, NICHT einfügen
// do not insert duplicate // keine Änderung am Baum
} }
else else
{ {
// duplicates allowed -> insert into right subtree // Duplikate erlaubt -> konventionell in den rechten Teilbaum einfügen
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
} }
} }
return root; return wurzel;
} }
// 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. void *nextTreeData(TreeNode *wurzel)
// 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)
{ {
static StackNode *iterStack = NULL; static StackNode *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg
// If a new tree root is provided -> reset iterator // Neuer Baum übergeben -> Iterator zurücksetzen/initialisieren
if(root != NULL) if (wurzel != NULL)
{ {
clearStack(iterStack); clearStack(iteratorStack); // ggf. alten Stack leeren (Speicher freigeben)
iterStack = NULL; iteratorStack = NULL; // Top-Zeiger zurücksetzen
bintree_pushLefts(&iterStack, root); bintree_pushLefts(&iteratorStack, wurzel); // Wurzel und linke Kette ablegen
} }
if(iterStack == NULL) // Kein weiterer Eintrag?
if (iteratorStack == NULL)
return NULL; return NULL;
TreeNode *node = (TreeNode *)top(iterStack); // Nächsten Knoten holen (oberstes Stack-Element)
iterStack = pop(iterStack); TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack);
iteratorStack = pop(iteratorStack);
if(node->right != NULL) // Falls rechter Teilbaum existiert: dessen linke Kette ablegen
bintree_pushLefts(&iterStack, node->right); 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; return;
clearTree(root->left); clearTree(wurzel->left);
clearTree(root->right); clearTree(wurzel->right);
free(root->data); free(wurzel->data);
free(root); 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 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 #ifndef BINTREE_H
#define BINTREE_H #define BINTREE_H
#include <stdlib.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); 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 typedef struct node
{ {
void *data; void *data; // Zeiger auf die Nutzdaten
struct node *left; struct node *left; // Zeiger auf linken Kindknoten
struct node *right; struct node *right; // Zeiger auf rechten Kindknoten
} TreeNode; } 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); 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); 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); 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); unsigned int treeSize(const TreeNode *root);
#endif #endif