This commit is contained in:
Nicolas Reckert 2025-12-15 13:18:13 +01:00
parent d0f2ee5760
commit 5ed4a367c8
6 changed files with 225 additions and 39 deletions

View File

@ -1,36 +1,133 @@
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "stack.h"
#include "bintree.h" #include "bintree.h"
#include "stack.h"
//TODO: binären Suchbaum implementieren /* Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). */
* `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).
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)
{ {
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;
} }
// 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. int cmp = compareFct(data, root->data);
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, if (cmp < 0)
// push the top node and push all its left nodes. {
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 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) 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;
} }
// Releases all memory resources (including data copies). // 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). */
void clearTree(TreeNode *root) 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) unsigned int treeSize(const TreeNode *root)
{ {
if (root == NULL)
return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
} }

View File

@ -1 +1,2 @@
Test;4988
player1;3999 player1;3999

View File

@ -17,7 +17,7 @@ doble_initial:
doble : main.o $(program_obj_files) doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble $(CC) $(FLAGS) $^ -o doble
$(program_obj_filesobj_files): %.o: %.c $(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@ $(CC) -c $(FLAGS) $^ -o $@
# -------------------------- # --------------------------

View File

@ -5,22 +5,92 @@
#include "numbers.h" #include "numbers.h"
#include "bintree.h" #include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren // --- Hilfsfunktion: Vergleich von unsigned int ------------------
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. static int compareUInt(const void *a, const void *b)
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen. {
* Duplizieren eines zufälligen Eintrags im Array. unsigned int ua = *(const unsigned int *)a;
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ unsigned int ub = *(const unsigned int *)b;
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. if (ua < ub) return -1;
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while if (ua > ub) return 1;
// creating random numbers. 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.
unsigned int *createNumbers(unsigned int len) 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;
}
} }
// Returns only the only number in numbers which is present twice. Returns zero on errors. // 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) unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{ {
if (!numbers || len < 2)
return 0;
// 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;
} }

View File

@ -1,33 +1,45 @@
#include <stdlib.h> #include <stdlib.h>
#include "stack.h" #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. // Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data) 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 // Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be
// freed by caller.) // freed by caller.)
StackNode *pop(StackNode *stack) StackNode *pop(StackNode *stack)
{ {
if (stack == NULL)
return NULL;
StackNode *next = stack->next;
free(stack);
return next;
} }
// Returns the data of the top element. // Returns the data of the top element.
void *top(StackNode *stack) void *top(StackNode *stack)
{ {
if (stack == NULL)
return NULL;
return stack->data;
} }
// Clears stack and releases all memory. // Clears stack and releases all memory.
void clearStack(StackNode *stack) void clearStack(StackNode *stack)
{ {
while (stack != NULL)
{
StackNode *next = stack->next;
free(stack);
stack = next;
}
} }

View File

@ -8,6 +8,12 @@ The latest element is taken from the stack. */
#include <stdlib.h> #include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen //TODO: passenden Datentyp als struct anlegen
struct StackNode {
void *data;
struct StackNode *next;
};
typedef struct StackNode StackNode;
// Pushes data as pointer onto the stack. // Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data); StackNode *push(StackNode *stack, void *data);