This commit is contained in:
Kilian Muckelbauer 2025-12-15 21:04:35 +01:00
parent d56c77d77a
commit ed5f4eedc8
7 changed files with 97 additions and 43 deletions

View File

@ -2,126 +2,158 @@
#include "stack.h"
#include "bintree.h"
// 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 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)
{
// neuer Knoten
// 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
{
// Element bereits vorhanden
// Gleicher Wert → Duplikat
if (isDuplicate != NULL)
{
// Duplikat melden, aber nicht einfügen
*isDuplicate = 1;
// Duplikate werden ignoriert
}
else
{
// Duplikate dürfen eingefügt werden -> wir hängen sie z.B. links an
// 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;
}
// Interner Stack für die Traversierung (strtok-ähnliches Verhalten)
// Globaler interner Stack für die Baum-Traversierung
// Ermöglicht ein strtok-ähnliches Iterator-Verhalten
static StackNode *iterStack = NULL;
// Hilfsfunktion: legt ab start alle linken Knoten auf den Stack
// 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;
}
}
// 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.
// 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 aufräumen
// 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;
// Nächsten Knoten holen
// Oberstes Stack-Element holen (nächster Baumknoten)
TreeNode *node = (TreeNode *)top(iterStack);
iterStack = pop(iterStack);
// rechten Teilbaum dieses Knotens auf den Stack bringen
// 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;
}
// Releases all memory resources (including data copies).
// 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);
}
// Returns the number of entries in the tree given by 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);
}

BIN
bintree.o

Binary file not shown.

BIN
doble.exe

Binary file not shown.

View File

@ -1,3 +1,4 @@
Kilian;9927
Kilian;9915
Kilian;4975
player1;3999

View File

@ -12,91 +12,109 @@
* - Fehlerfälle (NULL-Pointer, zu kleine Länge)
*/
/*
* Prüft ein Zahlenarray auf Korrektheit:
* - Array darf nicht NULL sein
* - Wertebereich muss stimmen
* - genau eine Zahl darf doppelt vorkommen
*/
static void check_numbers_array(unsigned int *numbers, unsigned int len)
{
unsigned int maxValue = 2 * len;
unsigned int *counts;
unsigned int maxValue = 2 * len; // Maximal erlaubter Zahlenwert
unsigned int *counts; // Array zum Zählen der Vorkommen
unsigned int i;
unsigned int duplicatesCount = 0;
unsigned int duplicatesCount = 0; // Zähler für doppelte Werte
assert(numbers != NULL);
assert(numbers != NULL); // Sicherstellen, dass das Array existiert
// Speicher für Zähler-Array reservieren und mit 0 initialisieren
counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
assert(counts != NULL);
assert(counts != NULL); // Prüfen, ob Speicher erfolgreich reserviert wurde
// Werte zählen und Bereich prüfen
// Schleife über alle Elemente des numbers-Arrays
// Zählt die Werte und prüft gleichzeitig den gültigen Wertebereich
for (i = 0; i < len; ++i)
{
unsigned int v = numbers[i];
assert(v >= 1 && v <= maxValue);
counts[v]++;
unsigned int v = numbers[i]; // Aktueller Wert
assert(v >= 1 && v <= maxValue); // Wertebereich prüfen
counts[v]++; // Anzahl dieses Wertes erhöhen
}
// Prüfen: genau eine Zahl kommt zweimal vor, alle anderen höchstens einmal
// Schleife über alle möglichen Werte
// Prüft, dass genau ein Wert doppelt vorkommt
for (i = 1; i <= maxValue; ++i)
{
if (counts[i] == 2)
duplicatesCount++;
duplicatesCount++; // Ein doppelter Wert gefunden
else
assert(counts[i] == 0 || counts[i] == 1);
assert(counts[i] == 0 || counts[i] == 1); // Alle anderen max. einmal
}
assert(duplicatesCount == 1);
assert(duplicatesCount == 1); // Es darf genau ein Duplikat geben
free(counts);
free(counts); // Speicher freigeben
}
/*
* Testet createNumbers und getDuplicate für eine gegebene Länge
*/
static void test_createNumbers_and_getDuplicate(unsigned int len)
{
printf("test_createNumbers_and_getDuplicate(len=%u)...\n", len);
// Zahlenarray erzeugen
unsigned int *numbers = createNumbers(len);
assert(numbers != NULL);
assert(numbers != NULL); // Rückgabewert prüfen
// Arraystruktur überprüfen
// Struktur und Inhalt des Arrays überprüfen
check_numbers_array(numbers, len);
// Nochmal zählen, um das Duplikat zu kennen
// Erneutes Zählen, um das erwartete Duplikat zu ermitteln
unsigned int maxValue = 2 * len;
unsigned int *counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
assert(counts != NULL);
// Schleife zum Zählen aller Werte
for (unsigned int i = 0; i < len; ++i)
{
unsigned int v = numbers[i];
counts[v]++;
}
// Schleife zur Bestimmung des doppelten Wertes
unsigned int expectedDuplicate = 0;
for (unsigned int v = 1; v <= maxValue; ++v)
{
if (counts[v] == 2)
{
expectedDuplicate = v;
expectedDuplicate = v; // Doppelten Wert merken
break;
}
}
assert(expectedDuplicate != 0);
assert(expectedDuplicate != 0); // Es muss ein Duplikat existieren
// getDuplicate testen
// getDuplicate-Funktion testen
unsigned int found = getDuplicate(numbers, len);
assert(found == expectedDuplicate);
assert(found == expectedDuplicate); // Ergebnis vergleichen
free(counts);
free(counts); // Speicher freigeben
free(numbers);
printf("...OK\n");
}
/*
* Testet Fehlerfälle für getDuplicate
*/
static void test_getDuplicate_error_cases(void)
{
printf("test_getDuplicate_error_cases...\n");
// NULL-Array
// Test mit NULL-Pointer
unsigned int dup = getDuplicate(NULL, 10);
assert(dup == 0);
// Länge < 2
// Test mit zu kleiner Länge (< 2)
unsigned int dummy[1] = {42};
dup = getDuplicate(dummy, 1);
assert(dup == 0);
@ -104,16 +122,19 @@ static void test_getDuplicate_error_cases(void)
printf("...OK\n");
}
/*
* Hauptfunktion: startet alle Unit-Tests
*/
int main(void)
{
printf("Running numbers unit tests...\n\n");
// Typische Testfälle mit verschiedenen Längen
// Typische Testfälle mit unterschiedlichen Array-Längen
test_createNumbers_and_getDuplicate(5);
test_createNumbers_and_getDuplicate(10);
test_createNumbers_and_getDuplicate(20);
// Fehlerfälle
// Test der Fehlerfälle
test_getDuplicate_error_cases();
printf("\nAll numbers tests passed.\n");

Binary file not shown.

Binary file not shown.