From 5ed4a367c861bfd1fc7e575aaaff5ff4b7345d0c Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 15 Dec 2025 13:18:13 +0100 Subject: [PATCH] Bintree --- Start_Windows/bintree.c | 129 ++++++++++++++++++++++++++++++----- Start_Windows/highscores.txt | 1 + Start_Windows/makefile | 2 +- Start_Windows/numbers.c | 94 +++++++++++++++++++++---- Start_Windows/stack.c | 30 +++++--- Start_Windows/stack.h | 8 ++- 6 files changed, 225 insertions(+), 39 deletions(-) diff --git a/Start_Windows/bintree.c b/Start_Windows/bintree.c index 5cf82a9..cd1695f 100644 --- a/Start_Windows/bintree.c +++ b/Start_Windows/bintree.c @@ -1,36 +1,133 @@ +#include #include -#include "stack.h" #include "bintree.h" +#include "stack.h" -//TODO: binären Suchbaum implementieren -/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), - * `clearTree`: gibt den gesamten Baum frei (rekursiv), - * `treeSize`: zählt die Knoten im Baum (rekursiv), - * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ - -// 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). +/* 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). */ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { + if (compareFct == NULL || data == NULL || dataSize == 0) + return root; // invalid input: do nothing + if (root == NULL) + { + TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode)); + if (node == NULL) + return NULL; // allocation failed + + node->data = malloc(dataSize); + if (node->data == NULL) + { + free(node); + return NULL; + } + memcpy(node->data, data, dataSize); + node->left = NULL; + node->right = NULL; + + if (isDuplicate != NULL) + *isDuplicate = 0; + + return node; + } + + int cmp = compareFct(data, root->data); + if (cmp < 0) + { + root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); + } + else if (cmp > 0) + { + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + else // cmp == 0 -> duplicate + { + if (isDuplicate != NULL) + { + *isDuplicate = 1; + // ignore duplicate insertion + } + else + { + // duplicates allowed: insert to right subtree for stability + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + } + + return root; } -// 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. +/* 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. */ void *nextTreeData(TreeNode *root) { + // static iterator state + static StackNode *iterStack = NULL; + // initialize iterator for a new tree + if (root != NULL) + { + // clear any previous iterator state + clearStack(iterStack); + iterStack = NULL; + + // push root and all its left descendants + TreeNode *cur = root; + while (cur != NULL) + { + iterStack = push(iterStack, cur); + cur = cur->left; + } + } + else + { + // if user asks to continue but iterator not initialized, nothing to return + if (iterStack == NULL) + return NULL; + } + + // get next node + if (iterStack == NULL) + return NULL; + + // pop the top node + TreeNode *node = (TreeNode *)top(iterStack); + iterStack = pop(iterStack); + + // after popping node, push its right child and all left descendants of that right child + TreeNode *r = node->right; + while (r != NULL) + { + iterStack = push(iterStack, r); + r = r->left; + } + + return node->data; } -// Releases all memory resources (including data copies). +/* Releases all memory resources (including data copies). */ void clearTree(TreeNode *root) { + if (root == NULL) + return; + if (root->left != NULL) + clearTree(root->left); + if (root->right != NULL) + clearTree(root->right); + + free(root->data); + root->data = NULL; + free(root); } -// Returns the number of entries in the tree given by root. +/* Returns the number of entries in the tree given by root. */ unsigned int treeSize(const TreeNode *root) { - -} \ No newline at end of file + if (root == NULL) + return 0; + return 1 + treeSize(root->left) + treeSize(root->right); +} diff --git a/Start_Windows/highscores.txt b/Start_Windows/highscores.txt index 4edd5a7..94e9023 100644 --- a/Start_Windows/highscores.txt +++ b/Start_Windows/highscores.txt @@ -1 +1,2 @@ +Test;4988 player1;3999 diff --git a/Start_Windows/makefile b/Start_Windows/makefile index b67312a..1323c45 100644 --- a/Start_Windows/makefile +++ b/Start_Windows/makefile @@ -17,7 +17,7 @@ doble_initial: doble : main.o $(program_obj_files) $(CC) $(FLAGS) $^ -o doble -$(program_obj_filesobj_files): %.o: %.c +$(program_obj_files): %.o: %.c $(CC) -c $(FLAGS) $^ -o $@ # -------------------------- diff --git a/Start_Windows/numbers.c b/Start_Windows/numbers.c index f59d9a2..5774a08 100644 --- a/Start_Windows/numbers.c +++ b/Start_Windows/numbers.c @@ -5,22 +5,92 @@ #include "numbers.h" #include "bintree.h" -//TODO: getDuplicate und createNumbers implementieren -/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. - * Sicherstellen, dass beim Befüllen keine Duplikate entstehen. - * Duplizieren eines zufälligen Eintrags im Array. - * in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ - -// 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. -unsigned int *createNumbers(unsigned int len) +// --- Hilfsfunktion: Vergleich von unsigned int ------------------ +static int compareUInt(const void *a, const void *b) { + unsigned int ua = *(const unsigned int *)a; + unsigned int ub = *(const unsigned int *)b; + if (ua < ub) return -1; + if (ua > ub) return 1; + return 0; } -// Returns only the only number in numbers which is present twice. Returns zero on errors. +// 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. +unsigned int *createNumbers(unsigned int len) +{ + if (len < 2) + return NULL; + + unsigned int *arr = malloc(sizeof(unsigned int) * len); + if (!arr) + return NULL; + + srand((unsigned int)time(NULL)); + + TreeNode *root = NULL; + + unsigned int count = 0; + while (count < len - 1) // generate len-1 UNIQUE numbers + { + unsigned int val = (rand() % (2 * len)) + 1; + + int isDup = 0; + root = addToTree(root, &val, sizeof(unsigned int), compareUInt, &isDup); + + if (!isDup) + { + arr[count++] = val; + } + } + + // pick a random existing value to duplicate + unsigned int duplicateIndex = rand() % (len - 1); + arr[len - 1] = arr[duplicateIndex]; + + clearTree(root); + return arr; +} + +// Returns the only number in the array that occurs twice. unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + if (!numbers || len < 2) + return 0; -} \ No newline at end of file + // copy array + unsigned int *copy = malloc(sizeof(unsigned int) * len); + if (!copy) + return 0; + + memcpy(copy, numbers, sizeof(unsigned int) * len); + + // sort + for (unsigned int i = 0; i < len - 1; i++) + { + for (unsigned int j = i + 1; j < len; j++) + { + if (copy[j] < copy[i]) + { + unsigned int t = copy[i]; + copy[i] = copy[j]; + copy[j] = t; + } + } + } + + // find adjacent duplicate + unsigned int duplicate = 0; + for (unsigned int i = 0; i < len - 1; i++) + { + if (copy[i] == copy[i + 1]) + { + duplicate = copy[i]; + break; + } + } + + free(copy); + return duplicate; +} diff --git a/Start_Windows/stack.c b/Start_Windows/stack.c index e3a90d4..b8c0f65 100644 --- a/Start_Windows/stack.c +++ b/Start_Windows/stack.c @@ -1,33 +1,45 @@ #include #include "stack.h" -//TODO: grundlegende Stackfunktionen implementieren: -/* * `push`: legt ein Element oben auf den Stack, - * `pop`: entfernt das oberste Element, - * `top`: liefert das oberste Element zurück, - * `clearStack`: gibt den gesamten Speicher frei. */ - // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data) { + StackNode *newNode = (StackNode *)malloc(sizeof(StackNode)); + if (newNode == NULL) + return stack; // allocation failed: return unchanged stack + newNode->data = data; + newNode->next = stack; + return newNode; } // Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be // freed by caller.) StackNode *pop(StackNode *stack) { + if (stack == NULL) + return NULL; + StackNode *next = stack->next; + free(stack); + return next; } // Returns the data of the top element. void *top(StackNode *stack) { - + if (stack == NULL) + return NULL; + return stack->data; } // Clears stack and releases all memory. void clearStack(StackNode *stack) { - -} \ No newline at end of file + while (stack != NULL) + { + StackNode *next = stack->next; + free(stack); + stack = next; + } +} diff --git a/Start_Windows/stack.h b/Start_Windows/stack.h index f7d542d..0db2dd7 100644 --- a/Start_Windows/stack.h +++ b/Start_Windows/stack.h @@ -8,6 +8,12 @@ The latest element is taken from the stack. */ #include //TODO: passenden Datentyp als struct anlegen +struct StackNode { + void *data; + struct StackNode *next; +}; + +typedef struct StackNode StackNode; // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data); @@ -22,4 +28,4 @@ void *top(StackNode *stack); // Clears stack and releases all memory. void clearStack(StackNode *stack); -#endif +#endif \ No newline at end of file