From a3f8aedb26d42ed64ee4cdc980774817a1467d17 Mon Sep 17 00:00:00 2001 From: manusmac Date: Mon, 12 Jan 2026 14:23:46 +0100 Subject: [PATCH] bintree fehler im struct behoben und nubers rest impementiert doble spiel funktioniert jetzt --- bintree.c | 171 ++++++++++++++++++++++++++++++++----------------- bintree.h | 7 +- highscores.txt | 3 + numbers.c | 142 +++++++++++++++++++++++++++++++--------- 4 files changed, 231 insertions(+), 92 deletions(-) diff --git a/bintree.c b/bintree.c index 0ff1c53..ecdf4d6 100644 --- a/bintree.c +++ b/bintree.c @@ -12,96 +12,153 @@ // if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // Hilfsfunktion: neuen Knoten erstellen und Daten kopieren -TreeNode* newNode(const void* data, size_t dataSize) { - TreeNode* node = malloc(sizeof(TreeNode)); - if (!node) return NULL; - +static TreeNode* createNode(const void* data, size_t dataSize) +{ + TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); + if (node == NULL) + { + return NULL; + } + node->data = malloc(dataSize); - if (!node->data) { + if (node->data == NULL) + { free(node); return NULL; } - memcpy(node->data, data, dataSize); // Daten kopieren - node->left = node->right = NULL; + + memcpy(node->data, data, dataSize); + // dataSize wird NICHT im struct gespeichert, da es nicht im Header ist + node->left = NULL; + node->right = NULL; + return node; } -TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, + +// Fügt eine Kopie der Daten in den Baum ein (rekursiv) +TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { - if (root == NULL) { - *isDuplicate = 0; // kein Duplikat, neuer Knoten - return newNode(data, dataSize); // neuer Knoten wird Wurzel + // Basisfall: leerer Baum oder Blattknoten erreicht + if (root == NULL) + { + // isDuplicate auf 0 setzen, wenn nicht NULL + if (isDuplicate != NULL) + { + *isDuplicate = 0; + } + + return createNode(data, dataSize); } - + + // Daten vergleichen int result = compareFct(data, root->data); - - if (result < 0) { + + if (result < 0) + { + // Daten sind kleiner -> in linken Teilbaum einfügen root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); - } else if (result > 0) { - root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); - } else { - // result == 0 → Duplikat - *isDuplicate = 1; } - + else if (result > 0) + { + // Daten sind größer -> in rechten Teilbaum einfügen + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + else + { + // result == 0 → Duplikat gefunden + if (isDuplicate != NULL) + { + *isDuplicate = 1; // Duplikat, nicht einfügen + } + else + { + // Duplikate sind erlaubt -> in rechten Teilbaum einfügen + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + } + return root; } +// Statischer Stack für die Iterator-Funktion (wie bei strtok) +static StackNode *iteratorStack = NULL; -// 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. -// Initialisiert den Stack mit der Wurzel und allen linken Nachfolgern -StackNode* initTraversal(TreeNode* root) { - StackNode* stack = NULL; - TreeNode* current = root; - - while (current != NULL) { - stack = push(stack, current); - current = current->left; +// Iteriert über den Baum (In-Order-Traversierung mit Stack) +// Funktioniert wie strtok: beim ersten Aufruf root übergeben, dann NULL +void *nextTreeData(TreeNode *root) +{ + // Wenn root != NULL: neuer Iterator-Durchlauf starten + if (root != NULL) + { + // Alten Stack löschen, falls vorhanden + clearStack(iteratorStack); + iteratorStack = NULL; + + // Alle linken Knoten auf den Stack pushen (bis zum kleinsten Element) + TreeNode *current = root; + while (current != NULL) + { + iteratorStack = push(iteratorStack, current); + current = current->left; + } } - return stack; -} -void* nextTreeData(StackNode** stack) { - if (*stack == NULL) { - return NULL; // Traversierung beendet - - // Obersten Knoten holen - TreeNode* node = (TreeNode*)top(*stack); - *stack = pop(*stack); - - // Falls rechter Teilbaum existiert, diesen und alle linken Nachfolger auf den Stack legen - TreeNode* current = node->right; - while (current != NULL) { - *stack = push(*stack, current); - current = current->left; + + // Wenn Stack leer ist, sind wir fertig + if (iteratorStack == NULL) + { + return NULL; } - + + // Oberstes Element vom Stack holen + TreeNode *node = (TreeNode *)top(iteratorStack); + iteratorStack = pop(iteratorStack); + + // Wenn der Knoten einen rechten Teilbaum hat, + // alle linken Knoten des rechten Teilbaums auf den Stack pushen + if (node->right != NULL) + { + TreeNode *current = node->right; + while (current != NULL) + { + iteratorStack = push(iteratorStack, current); + current = current->left; + } + } + + // Daten des aktuellen Knotens zurückgeben return node->data; -}} +} -// Releases all memory resources (including data copies). +// Gibt den gesamten Baum frei (rekursiv, Post-Order) void clearTree(TreeNode *root) { - if (root == NULL) return; // Basisfall: leerer Teilbaum - - // Rekursiv zuerst die Kinder freigeben + if (root == NULL) + { + return; // Basisfall: leerer Teilbaum + } + + // Erst linken Teilbaum löschen clearTree(root->left); + + // Dann rechten Teilbaum löschen clearTree(root->right); - - // Daten freigeben + + // Dann Daten und Knoten selbst löschen free(root->data); // Knoten selbst freigeben free(root); } -// Returns the number of entries in the tree given by root. +// Zählt die Knoten im Baum (rekursiv) unsigned int treeSize(const TreeNode *root) { - if (root == NULL) { + if (root == NULL) + { return 0; // Basisfall: leerer Teilbaum } - // Rekursiv: Größe = 1 (aktueller Knoten) + Größe des linken Teilbaums + Größe des rechten Teilbaums + + // Rekursiv: Größe = 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum return 1 + treeSize(root->left) + treeSize(root->right); } \ No newline at end of file diff --git a/bintree.h b/bintree.h index 25e16b2..4cb226d 100644 --- a/bintree.h +++ b/bintree.h @@ -7,9 +7,10 @@ typedef int (*CompareFctType)(const void *arg1, const void *arg2); typedef struct node { - void *data; - struct node *left; - struct node *right; + void *data; // Zeiger auf die Daten + size_t dataSize; // ← NEU: Größe der Daten + struct node *left; // Linker Teilbaum + struct node *right; // Rechter Teilbaum } TreeNode; // Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates diff --git a/highscores.txt b/highscores.txt index 4edd5a7..43e141f 100644 --- a/highscores.txt +++ b/highscores.txt @@ -1 +1,4 @@ +manu;9959 +manu;9949 +player2;9925 player1;3999 diff --git a/numbers.c b/numbers.c index 01e1405..47e610f 100644 --- a/numbers.c +++ b/numbers.c @@ -5,6 +5,18 @@ #include "numbers.h" #include "bintree.h" + +// Vergleichsfunktion für unsigned int (für Binärbaum und qsort) +static int compareUnsignedInt(const void *a, const void *b) +{ + unsigned int valA = *(unsigned int *)a; + unsigned int valB = *(unsigned int *)b; + + if (valA < valB) return -1; + if (valA > valB) return 1; + return 0; +} + // TODO: getDuplicate und createNumbers implementieren /* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. * Sicherstellen, dass beim Befüllen keine Duplikate entstehen. @@ -14,44 +26,110 @@ // Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. // Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while // creating random numbers. +// Erzeugt ein Array mit len eindeutigen Zufallszahlen zwischen 1 und 2*len +// Verwendet Binärbaum zur Duplikatsvermeidung +// Gibt dann eine zufällige Zahl doppelt zurück unsigned int *createNumbers(unsigned int len) { - - int n; - printf("Wie viele Zufallszahlen sollen erstellt werden? "); - scanf("%d", &n); - - int array[n]; - srand(time(NULL)); // Zufallsgenerator initialisieren - - for (int i = 0; i < n; i++) - { - int zahl; - char vorhanden; - + // Eingabevalidierung + if (len == 0) + { + return NULL; + } + + // Array allokieren + unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (numbers == NULL) + { + return NULL; + } + + // Binärbaum zur Duplikatsprüfung erstellen + TreeNode *tree = NULL; + + // Zufallsgenerator initialisieren + static int seedInitialized = 0; + if (!seedInitialized) + { + srand(time(NULL)); + seedInitialized = 1; + } + + // Zufallszahlen zwischen 1 und 2*len generieren (keine Duplikate) + unsigned int inserted = 0; + while (inserted < len) + { + // Zufallszahl zwischen 1 und 2*len generieren + unsigned int randomNum = (rand() % (2 * len)) + 1; + + // In Baum einfügen und prüfen, ob Duplikat + int isDuplicate = 0; + tree = addToTree(tree, &randomNum, sizeof(unsigned int), + compareUnsignedInt, &isDuplicate); + + // Wenn kein Duplikat, ins Array einfügen + if (!isDuplicate) + { + numbers[inserted] = randomNum; + inserted++; + } + } + + // Baum aufräumen + clearTree(tree); + + // Einen zufälligen Eintrag duplizieren + // Wähle zwei verschiedene Indizes + unsigned int sourceIndex = rand() % len; + unsigned int targetIndex; + do { - vorhanden = 0; - zahl = rand() % n; // Zufallszahl zwischen 1 und 100 - - // Prüfen, ob Zahl schon im Array existiert - for (int j = 0; j < i; j++) - { - if (array[j] == zahl) - { - vorhanden = 1; - break; - } - } - } while (vorhanden); // solange wiederholen, bis Zahl einzigartig ist - - array[i] = zahl; - } - - return 0; + targetIndex = rand() % len; + } while (targetIndex == sourceIndex); + + // Kopiere Wert von source nach target (erzeugt Duplikat) + numbers[targetIndex] = numbers[sourceIndex]; + + return numbers; } -// Returns only the only number in numbers which is present twice. Returns zero on errors. +// Findet das Duplikat durch Sortieren und Vergleich benachbarter Elemente +// Gibt 0 bei Fehlern zurück unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + // Eingabevalidierung + if (numbers == NULL || len < 2) + { + return 0; // Fehler + } + + // Kopie des Arrays erstellen (um Original nicht zu verändern) + unsigned int *sortedNumbers = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (sortedNumbers == NULL) + { + return 0; // Speicherfehler + } + + // Array kopieren + memcpy(sortedNumbers, numbers, len * sizeof(unsigned int)); + + // Array mit qsort sortieren + qsort(sortedNumbers, len, sizeof(unsigned int), compareUnsignedInt); + + // Benachbarte Elemente vergleichen, um Duplikat zu finden + unsigned int duplicate = 0; + for (unsigned int i = 0; i < len - 1; i++) + { + if (sortedNumbers[i] == sortedNumbers[i + 1]) + { + duplicate = sortedNumbers[i]; + break; + } + } + + // Aufräumen + free(sortedNumbers); + + return duplicate; } \ No newline at end of file