Compare commits
No commits in common. "23dccdfd8dabb6378c650c4ea79b379b8192b441" and "416f44ae748137c160afdc85643c0b4e22fdb10a" have entirely different histories.
23dccdfd8d
...
416f44ae74
165
bintree.c
165
bintree.c
@ -1,148 +1,111 @@
|
|||||||
|
|
||||||
#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
|
||||||
Schiebt einen Knoten und alle seine linken Nachfolger
|
static void bintree_pushLefts(StackNode **iterStackPtr, TreeNode *n)
|
||||||
(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)
|
while(n != NULL)
|
||||||
{
|
{
|
||||||
*iterStackPtr = push(*iterStackPtr, knoten); // aktuellen Knoten oben auf den Stack legen
|
*iterStackPtr = push(*iterStackPtr, n);
|
||||||
knoten = knoten->left; // zum linken Kind weiterlaufen
|
n = n->left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
|
||||||
Fügt eine Kopie der Daten (Speicherbereich von 'data' mit Länge 'dataSize') in den Baum ein.
|
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
|
||||||
Die Ordnung wird über 'compareFct' festgelegt.
|
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
|
||||||
|
|
||||||
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(isDuplicate != NULL)
|
||||||
if (istDuplikat != NULL)
|
*isDuplicate = 0;
|
||||||
*istDuplikat = 0;
|
|
||||||
|
|
||||||
// Leerer Baum/Teilbaum: neuen Knoten erzeugen
|
if(root == NULL)
|
||||||
if (wurzel == NULL)
|
|
||||||
{
|
{
|
||||||
TreeNode *neuerKnoten = (TreeNode *)malloc(sizeof(TreeNode));
|
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
|
||||||
if (neuerKnoten == NULL)
|
if(node == NULL)
|
||||||
return NULL; // Speicherfehler
|
return NULL;
|
||||||
|
node->data = malloc(dataSize);
|
||||||
neuerKnoten->data = malloc(datenGroesse);
|
if(node->data == NULL)
|
||||||
if (neuerKnoten->data == NULL)
|
|
||||||
{
|
{
|
||||||
free(neuerKnoten);
|
free(node);
|
||||||
return NULL; // Speicherfehler für Datenbereich
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(node->data, data, dataSize);
|
||||||
|
node->left = node->right = NULL;
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(neuerKnoten->data, daten, datenGroesse); // tiefe Kopie der Nutzdaten
|
int cmp = compareFct(data, root->data);
|
||||||
neuerKnoten->left = neuerKnoten->right = NULL; // Blatt
|
if(cmp < 0)
|
||||||
return neuerKnoten;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vergleich der einzufügenden Daten mit dem aktuellen Knoten
|
|
||||||
int vergleich = vergleichFkt(daten, wurzel->data);
|
|
||||||
|
|
||||||
if (vergleich < 0)
|
|
||||||
{
|
{
|
||||||
// links einfügen
|
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||||
wurzel->left = addToTree(wurzel->left, daten, datenGroesse, vergleichFkt, istDuplikat);
|
|
||||||
}
|
}
|
||||||
else if (vergleich > 0)
|
else if(cmp > 0)
|
||||||
{
|
{
|
||||||
// rechts einfügen
|
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||||
wurzel->right = addToTree(wurzel->right, daten, datenGroesse, vergleichFkt, istDuplikat);
|
}
|
||||||
|
else // equal
|
||||||
|
{
|
||||||
|
if(isDuplicate != NULL)
|
||||||
|
{
|
||||||
|
*isDuplicate = 1;
|
||||||
|
// do not insert duplicate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Gleichheit (potenzielles Duplikat)
|
// duplicates allowed -> insert into right subtree
|
||||||
if (istDuplikat != NULL)
|
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||||
{
|
|
||||||
*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;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *nextTreeData(TreeNode *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.
|
||||||
|
// 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 *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg
|
static StackNode *iterStack = NULL;
|
||||||
|
|
||||||
// Neuer Baum übergeben -> Iterator zurücksetzen/initialisieren
|
// If a new tree root is provided -> reset iterator
|
||||||
if (wurzel != NULL)
|
if(root != NULL)
|
||||||
{
|
{
|
||||||
clearStack(iteratorStack); // ggf. alten Stack leeren (Speicher freigeben)
|
clearStack(iterStack);
|
||||||
iteratorStack = NULL; // Top-Zeiger zurücksetzen
|
iterStack = NULL;
|
||||||
bintree_pushLefts(&iteratorStack, wurzel); // Wurzel und linke Kette ablegen
|
bintree_pushLefts(&iterStack, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kein weiterer Eintrag?
|
if(iterStack == NULL)
|
||||||
if (iteratorStack == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Nächsten Knoten holen (oberstes Stack-Element)
|
TreeNode *node = (TreeNode *)top(iterStack);
|
||||||
TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack);
|
iterStack = pop(iterStack);
|
||||||
iteratorStack = pop(iteratorStack);
|
|
||||||
|
|
||||||
// Falls rechter Teilbaum existiert: dessen linke Kette ablegen
|
if(node->right != NULL)
|
||||||
if (aktuellerKnoten->right != NULL)
|
bintree_pushLefts(&iterStack, node->right);
|
||||||
bintree_pushLefts(&iteratorStack, aktuellerKnoten->right);
|
|
||||||
|
|
||||||
// Daten des aktuellen Knotens zurückgeben
|
return node->data;
|
||||||
return aktuellerKnoten->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Releases all memory resources (including data copies).
|
||||||
Gibt den gesamten Baum frei (inkl. der tief kopierten Daten).
|
void clearTree(TreeNode *root)
|
||||||
*/
|
|
||||||
void clearTree(TreeNode *wurzel)
|
|
||||||
{
|
{
|
||||||
if (wurzel == NULL)
|
if(root == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clearTree(wurzel->left);
|
clearTree(root->left);
|
||||||
clearTree(wurzel->right);
|
clearTree(root->right);
|
||||||
|
|
||||||
free(wurzel->data);
|
free(root->data);
|
||||||
free(wurzel);
|
free(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Returns the number of entries in the tree given by root.
|
||||||
Liefert die Anzahl der Knoten/Einträge im Teilbaum 'wurzel'.
|
unsigned int treeSize(const TreeNode *root)
|
||||||
*/
|
|
||||||
unsigned int treeSize(const TreeNode *wurzel)
|
|
||||||
{
|
{
|
||||||
if (wurzel == NULL)
|
if(root == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
return 1 + treeSize(root->left) + treeSize(root->right);
|
||||||
return 1U + treeSize(wurzel->left) + treeSize(wurzel->right);
|
|
||||||
}
|
}
|
||||||
74
bintree.h
74
bintree.h
@ -1,81 +1,27 @@
|
|||||||
|
|
||||||
#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; // Zeiger auf die Nutzdaten
|
void *data;
|
||||||
struct node *left; // Zeiger auf linken Kindknoten
|
struct node *left;
|
||||||
struct node *right; // Zeiger auf rechten Kindknoten
|
struct node *right;
|
||||||
} TreeNode;
|
} TreeNode;
|
||||||
|
|
||||||
/*
|
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
|
||||||
Fügt eine Kopie der Daten in den Binärbaum ein.
|
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
|
||||||
|
|
||||||
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,
|
||||||
Iteriert über den Baum in Inorder-Reihenfolge.
|
// push the top node and push all its left nodes.
|
||||||
|
|
||||||
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
|
||||||
Loading…
x
Reference in New Issue
Block a user