From be3cb9e2fc990dfb59339906999dba861e097970 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 16 Dec 2025 11:45:12 +0100 Subject: [PATCH] Bintree, Numbers angepasst --- bintree.c | 59 +++++++++++++++++------------- numbers.c | 24 ++++++++---- test_numbers.c | 99 +++++++++++++++++++++++++++----------------------- 3 files changed, 103 insertions(+), 79 deletions(-) diff --git a/bintree.c b/bintree.c index ca0fe7c..3d5616e 100644 --- a/bintree.c +++ b/bintree.c @@ -3,18 +3,21 @@ #include "bintree.h" #include "stack.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 eine Kopie der Daten in den Baum ein, geordnet nach compareFct. Akzeptiert Duplikate, + wenn isDuplicate NULL ist, andernfalls ignoriert Duplikate und setzt isDuplicate auf 1 (oder auf 0 bei neuem Eintrag). */ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { + // Überprüfe ungültige Eingabeparameter if (compareFct == NULL || data == NULL || dataSize == 0) - return root; // invalid input: do nothing + return root; // ungültige Eingabe: nichts tun + // Wenn der Baum leer ist, erstelle einen neuen Wurzelknoten if (root == NULL) - { + +{ TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode)); if (node == NULL) - return NULL; // allocation failed + return NULL; // Speicherallokation fehlgeschlagen node->data = malloc(dataSize); if (node->data == NULL) @@ -31,26 +34,29 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFc return node; } - + // Vergleiche neue Daten mit aktueller Wurzel int cmp = compareFct(data, root->data); + // Wenn neue Daten kleiner sind, füge in linken Unterbaum ein if (cmp < 0) { root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); } + // Wenn neue Daten größer sind, füge in rechten Unterbaum ein else if (cmp > 0) { root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } - else // cmp == 0 -> duplicate + // Wenn gleich (Duplikat) + else { + // Wenn Duplikate erkannt werden sollen, setze Flag und ignoriere if (isDuplicate != NULL) { *isDuplicate = 1; - // ignore duplicate insertion } + // Andernfalls erlaube Duplikate durch Einfügen in rechten Unterbaum else { - // duplicates allowed: insert to right subtree for stability root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); } } @@ -58,25 +64,23 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFc return root; } -/* Iterates over the tree given by root in-order (ascending order). - Follows the usage of strtok: If root != NULL then create/reset iterator for that tree. - If root == NULL, continue iteration from last position. - Uses stack to manage traversal state. */ +/* Iteriert über den Baum in aufsteigender Reihenfolge (in-order). + Verwendet die Logik von strtok: Wenn root != NULL, initialisiere/reset Iterator für diesen Baum. + Wenn root == NULL, setze Iteration von letzter Position fort. + Verwendet Stack zur Verwaltung des Traversierungs-Zustands. */ void *nextTreeData(TreeNode *root) { - // static iterator state + // Statischer Stack zur Aufrechterhaltung des Iterator-Zustands zwischen Aufrufen static StackNode *iterStack = NULL; - static TreeNode *currentRoot = NULL; - // initialize iterator for a new tree + // Wenn ein neuer Baum bereitgestellt wird, initialisiere den Iterator if (root != NULL) { - // clear any previous iterator state + // Lösche vorherigen Iterator-Zustand clearStack(iterStack); iterStack = NULL; - currentRoot = root; - // push root and all its left descendants + // Pushe die Wurzel und alle linken Nachfahren auf den Stack TreeNode *cur = root; while (cur != NULL) { @@ -86,20 +90,20 @@ void *nextTreeData(TreeNode *root) } else { - // if user asks to continue but iterator not initialized, nothing to return + // Wenn Iteration fortgesetzt wird, aber kein Stack initialisiert, gib NULL zurück if (iterStack == NULL) return NULL; } - // get next node + // Wenn Stack leer ist, keine weiteren Elemente if (iterStack == NULL) return NULL; - // pop the top node + // Poppe den nächsten Knoten vom Stack (in-order-Traversierung) TreeNode *node = (TreeNode *)top(iterStack); iterStack = pop(iterStack); - // after popping node, push its right child and all left descendants of that right child + // Pushe den rechten Unterbaum des aktuellen Knotens und seine linken Nachfahren TreeNode *r = node->right; while (r != NULL) { @@ -110,26 +114,31 @@ void *nextTreeData(TreeNode *root) return node->data; } -/* Releases all memory resources (including data copies). */ +/* Gibt alle Speicherressourcen frei (einschließlich Datenkopien). */ void clearTree(TreeNode *root) { + // Basisfall: wenn Baum leer, nichts tun if (root == NULL) return; + // Rekursiv linken und rechten Unterbaum löschen if (root->left != NULL) clearTree(root->left); if (root->right != NULL) clearTree(root->right); + // Daten und Knoten selbst freigeben free(root->data); root->data = NULL; free(root); } -/* Returns the number of entries in the tree given by root. */ +/* Gibt die Anzahl der Einträge im Baum zurück. */ unsigned int treeSize(const TreeNode *root) { + // Basisfall: leerer Baum hat Größe 0 if (root == NULL) return 0; + // Größe ist 1 (aktueller Knoten) plus Größen der Unterbäume return 1 + treeSize(root->left) + treeSize(root->right); } diff --git a/numbers.c b/numbers.c index 5774a08..41d0388 100644 --- a/numbers.c +++ b/numbers.c @@ -16,27 +16,32 @@ static int compareUInt(const void *a, const void *b) return 0; } -// Returns len random numbers between 1 and 2x len in random order which are all different, -// except for two entries. Uses the binary search tree to avoid duplicates. +// Gibt ein Array mit len zufälligen Zahlen zwischen 1 und 2*len zurück, die alle unterschiedlich sind, +// außer zwei Einträgen (ein Duplikat). Verwendet den Binärbaum, um Duplikate zu vermeiden. unsigned int *createNumbers(unsigned int len) { + // Überprüfe ungültige Länge if (len < 2) return NULL; + // Allokiere Speicher für das Array unsigned int *arr = malloc(sizeof(unsigned int) * len); if (!arr) return NULL; + // Initialisiere Zufallszahlengenerator srand((unsigned int)time(NULL)); TreeNode *root = NULL; unsigned int count = 0; - while (count < len - 1) // generate len-1 UNIQUE numbers + // Generiere len-1 eindeutige Zahlen + while (count < len - 1) { unsigned int val = (rand() % (2 * len)) + 1; int isDup = 0; + // Füge in Baum ein und prüfe auf Duplikat root = addToTree(root, &val, sizeof(unsigned int), compareUInt, &isDup); if (!isDup) @@ -45,28 +50,30 @@ unsigned int *createNumbers(unsigned int len) } } - // pick a random existing value to duplicate + // Wähle einen zufälligen bestehenden Wert als Duplikat unsigned int duplicateIndex = rand() % (len - 1); arr[len - 1] = arr[duplicateIndex]; + // Baum freigeben clearTree(root); return arr; } -// Returns the only number in the array that occurs twice. +// Gibt die einzige Zahl im Array zurück, die zweimal vorkommt. unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + // Überprüfe ungültige Eingaben if (!numbers || len < 2) return 0; - // copy array + // Kopiere Array unsigned int *copy = malloc(sizeof(unsigned int) * len); if (!copy) return 0; memcpy(copy, numbers, sizeof(unsigned int) * len); - // sort + // Sortiere das Array (einfache Bubble-Sort) for (unsigned int i = 0; i < len - 1; i++) { for (unsigned int j = i + 1; j < len; j++) @@ -80,7 +87,7 @@ unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) } } - // find adjacent duplicate + // Finde angrenzendes Duplikat unsigned int duplicate = 0; for (unsigned int i = 0; i < len - 1; i++) { @@ -91,6 +98,7 @@ unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) } } + // Speicher freigeben free(copy); return duplicate; } diff --git a/test_numbers.c b/test_numbers.c index 28a3ebe..c6eb0c0 100644 --- a/test_numbers.c +++ b/test_numbers.c @@ -2,52 +2,59 @@ #include #include "numbers.h" -int main() { - printf("===== TEST NUMBERS =====\n"); - - unsigned int len = 20; - unsigned int *arr = createNumbers(len); - - if (arr == NULL) { - printf("FAIL: createNumbers returned NULL\n"); - return 1; - } - - // Check length: should contain len numbers - printf("PASS: createNumbers != NULL\n"); - - // Count duplicates — exactly one number must appear twice - int countDuplicate = 0; - +// Einfache Funktion, um zu zählen, wie oft eine Zahl im Array vorkommt +int countOccurrences(const unsigned int *arr, unsigned int len, unsigned int value) { + int count = 0; for (unsigned int i = 0; i < len; i++) { - for (unsigned int j = i + 1; j < len; j++) { - if (arr[i] == arr[j]) { - countDuplicate++; - } - } + if (arr[i] == value) count++; } - - if (countDuplicate != 1) { - printf("FAIL: Array must contain exactly one duplicate, found %d\n", countDuplicate); - free(arr); - return 1; - } - printf("PASS: exactly one duplicate\n"); - - unsigned int found = getDuplicate(arr, len); - printf("Duplicate found by getDuplicate(): %u\n", found); - - if (found == 0) { - printf("FAIL: getDuplicate returned 0\n"); - free(arr); - return 1; - } - - printf("PASS: getDuplicate\n"); - - free(arr); - printf("PASS: free array\n"); - - printf("ALL NUMBERS TESTS PASSED\n"); - return 0; + return count; } + +// Testfunktion für createNumbers und getDuplicate +void testNumbers(unsigned int len) { + printf("Teste mit Laenge %u:\n", len); + + // Erstelle Zahlenarray + unsigned int *numbers = createNumbers(len); + if (numbers == NULL) { + printf("Fehler: Konnte Array nicht erstellen.\n"); + return; + } + + // Gib Array aus + printf("Generierte Zahlen: "); + for (unsigned int i = 0; i < len; i++) { + printf("%u ", numbers[i]); + } + printf("\n"); + + // Finde Duplikat + unsigned int duplicate = getDuplicate(numbers, len); + printf("Gefundenes Duplikat: %u\n", duplicate); + + // Überprüfe, ob es genau zweimal vorkommt + int occ = countOccurrences(numbers, len, duplicate); + if (occ == 2) { + printf("Korrekte Überprüfung: %u kommt genau zweimal vor.\n", duplicate); + } else { + printf("Fehler: %u kommt %d mal vor (sollte 2 sein).\n", duplicate, occ); + } + + // Speicher freigeben + free(numbers); + printf("\n"); +} + +int main() { + printf("Testprogramm für numbers.c\n"); + printf("=========================\n\n"); + + // Teste mit verschiedenen Längen + testNumbers(5); + testNumbers(10); + testNumbers(20); + + printf("Tests abgeschlossen.\n"); + return 0; +} \ No newline at end of file