This commit is contained in:
F A 2025-12-08 14:00:19 +01:00
parent 25085b3778
commit 81e1483e9e
18 changed files with 368 additions and 72 deletions

131
bintree.c
View File

@ -1,36 +1,129 @@
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "bintree.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. */
// --------------------------
// Hilfsfunktion für Vergleich von unsigned int
// --------------------------
static int compareUint(const void *a, const void *b)
{
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
if (x < y) return -1;
if (x > y) return 1;
return 0;
}
// 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).
// --------------------------
// addToTree
// --------------------------
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
if (!compareFct)
compareFct = compareUint;
if (!root)
{
TreeNode *node = malloc(sizeof(TreeNode));
if (!node) return NULL;
node->data = malloc(dataSize);
if (!node->data)
{
free(node);
return NULL;
}
memcpy(node->data, data, dataSize);
node->left = node->right = NULL;
if (isDuplicate) *isDuplicate = 0;
return node;
}
int cmp = compareFct(data, root->data);
if (cmp == 0)
{
if (isDuplicate) *isDuplicate = 1;
return root;
}
else if (cmp < 0)
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
else
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.
void *nextTreeData(TreeNode *root)
{
}
// Releases all memory resources (including data copies).
// --------------------------
// clearTree
// --------------------------
void clearTree(TreeNode *root)
{
if (!root) return;
clearTree(root->left);
clearTree(root->right);
free(root->data);
free(root);
}
// Returns the number of entries in the tree given by root.
// --------------------------
// treeSize
// --------------------------
unsigned int treeSize(const TreeNode *root)
{
if (!root) return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
}
// --------------------------
// nextTreeData (In-Order Traversal mit Stack) minimal
// --------------------------
#include "stack.h"
void *nextTreeData(TreeNode *root)
{
static StackNode *stack = NULL;
static TreeNode *current = NULL;
if (root) current = root;
while (current)
{
stack = push(stack, current);
current = current->left;
}
if (!stack) return NULL;
TreeNode *node = top(stack);
stack = pop(stack);
current = node->right;
return node->data;
}
// --------------------------
// Zusätzliche Hilfsfunktion contains für numbers.c
// --------------------------
int contains(TreeNode *root, unsigned int value)
{
if (!root) return 0;
unsigned int nodeValue = *(unsigned int *)root->data;
if (value == nodeValue) return 1;
if (value < nodeValue) return contains(root->left, value);
return contains(root->right, value);
}
// --------------------------
// Hilfsfunktion insert für numbers.c
// --------------------------
TreeNode* insert(TreeNode *root, unsigned int value)
{
int isDup = 0;
return addToTree(root, &value, sizeof(unsigned int), compareUint, &isDup);
}
// --------------------------
// Hilfsfunktion freeTree für numbers.c
// --------------------------
void freeTree(TreeNode *root)
{
clearTree(root);
}

BIN
bintree.o Normal file

Binary file not shown.

BIN
doble.exe Normal file

Binary file not shown.

BIN
doble_initial.exe Normal file

Binary file not shown.

BIN
highscore.o Normal file

Binary file not shown.

View File

@ -1 +1,10 @@
player_name1;19827
player_name3;6985
jannik;5979
jannik;4991
jannik;4980
player1;3999
player_name;3995
player_name2;3994
player_name1;3993
player_name3;3990

BIN
main.o Normal file

Binary file not shown.

View File

@ -16,34 +16,68 @@ raylibfolder = ./raylib
unityfolder = ./unity
# --------------------------
# Initiales Programm bauen (zum ausprobieren)
# Hauptprogramm bauen
# --------------------------
doble_initial:
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
# --------------------------
# Selbst implementiertes Programm bauen
# --------------------------
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
doble: main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble
main.o: main.c
$(CC) -c $(FLAGS) main.c -o main.o
$(program_obj_filesobj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
# Unit Tests
# --------------------------
unitTests:
echo "needs to be implemented"
unitTests: test_stack test_numbers
./test_stack
./test_numbers
# --- Test Stack ---
test_stack: test_stack.o stack.o
$(CC) $(FLAGS) $^ -o test_stack
test_stack.o: test_stack.c stack.h
$(CC) -c $(FLAGS) test_stack.c -o test_stack.o
# --- Test Numbers ---
test_numbers: test_numbers.o numbers.o bintree.o stack.o
$(CC) $(FLAGS) $^ -o test_numbers
test_numbers.o: test_numbers.c numbers.h
$(CC) -c $(FLAGS) test_numbers.c -o test_numbers.o
# --------------------------
# Objektdateien
# --------------------------
stack.o: stack.c stack.h
$(CC) -c $(FLAGS) stack.c -o stack.o
bintree.o: bintree.c bintree.h stack.h
$(CC) -c $(FLAGS) bintree.c -o bintree.o
numbers.o: numbers.c numbers.h bintree.h
$(CC) -c $(FLAGS) numbers.c -o numbers.o
timer.o: timer.c timer.h
$(CC) -c $(FLAGS) timer.c -o timer.o
highscore.o: highscore.c highscore.h
$(CC) -c $(FLAGS) highscore.c -o highscore.o
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble
del /f *.o doble test_stack test_numbers
else
rm -f *.o doble
rm -f *.o doble test_stack test_numbers
endif

View File

@ -5,22 +5,83 @@
#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 zum Vergleichen von ints für Baum
static int compareInt(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
// Vergleichsfunktion für qsort (unsigned int, überlauf-sicher)
static int compareUnsigned(const void *a, const void *b) {
unsigned int ua = *(unsigned int*)a;
unsigned int ub = *(unsigned int*)b;
if (ua < ub) return -1;
if (ua > ub) return 1;
return 0;
}
// Hilfsfunktion: Prüft, ob Wert schon im Baum ist
static int contains(TreeNode *root, unsigned int value) {
if (!root) return 0;
unsigned int val = *(unsigned int*)root->data;
if (val == value) return 1;
if (value < val) return contains(root->left, value);
return contains(root->right, value);
}
// Erzeugt ein Array von len Zahlen zwischen 1 und 2*len, alle einzigartig,
// außer eine Zahl wird dupliziert.
unsigned int *createNumbers(unsigned int len) {
if (len == 0) return NULL;
unsigned int *numbers = malloc(len * sizeof(unsigned int));
if (!numbers) return NULL;
TreeNode *tree = NULL;
srand((unsigned int)time(NULL));
for (unsigned int i = 0; i < len - 1; i++) { // alle außer die Duplikate
unsigned int value;
do {
value = rand() % (2 * len) + 1;
} while (contains(tree, value));
int isDup = 0;
tree = addToTree(tree, &value, sizeof(value), compareInt, &isDup);
numbers[i] = value;
}
// Dupliziere zufällig eine Zahl
unsigned int dupIndex = rand() % (len - 1);
numbers[len - 1] = numbers[dupIndex];
// Speicher freigeben
clearTree(tree);
return numbers;
}
// Sortiert das Array und findet die einzige doppelte Zahl
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) {
if (!numbers || len < 2) return 0;
// Kopiere Array, da wir sortieren müssen
unsigned int *copy = malloc(len * sizeof(unsigned int));
if (!copy) return 0;
memcpy(copy, numbers, len * sizeof(unsigned int));
// qsort verwenden
qsort(copy, len, sizeof(unsigned int), compareUnsigned);
// Durchlauf und Nachbarn vergleichen
unsigned int dup = 0;
for (unsigned int i = 1; i < len; i++) {
if (copy[i] == copy[i - 1]) {
dup = copy[i];
break;
}
}
free(copy);
return dup;
}

BIN
numbers.o Normal file

Binary file not shown.

47
stack.c
View File

@ -1,33 +1,38 @@
#include <stdlib.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 onto the stack and returns new stack top
StackNode *push(StackNode *stack, void *data) {
StackNode *node = malloc(sizeof(StackNode));
if (!node) return stack; // allocation failed → leave stack unchanged
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
node->data = data;
node->next = stack;
return node; // new top
}
// 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)
{
// Removes the top element, frees node (NOT data), returns new top
StackNode *pop(StackNode *stack) {
if (stack == NULL) return NULL;
StackNode *next = stack->next;
free(stack);
return next; // new top
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
// Returns data of top node or NULL
void *top(StackNode *stack) {
if (!stack) return NULL;
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
}
// Frees entire stack (NOT data!)
void clearStack(StackNode *stack) {
while (stack != NULL) {
StackNode *next = stack->next;
free(stack);
stack = next;
}
}

16
stack.h
View File

@ -1,19 +1,23 @@
#ifndef STACK_H
#define STACK_H
/* A stack is a special type of queue which uses the LIFO (last in, first out) principle.
This means that with each new element all other elements are pushed deeper into the stack.
The latest element is taken from the stack. */
/* A stack is a special type of queue which uses the LIFO (last in, first out) principle.
This means that with each new element all other elements are pushed deeper into the stack.
The latest element is taken from the stack. */
#include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen
// passenden Datentyp als struct anlegen
typedef struct StackNode {
void *data; // Zeiger auf beliebige Daten
struct StackNode *next; // Zeiger auf das nächste Element im Stack
} StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data);
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be
// freed by caller.)
// 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);
// Returns the data of the top element.

BIN
stack.o Normal file

Binary file not shown.

49
test_numbers.c Normal file
View File

@ -0,0 +1,49 @@
#include <stdio.h>
#include <stdlib.h>
#include "numbers.h"
int main(void)
{
printf("=== TEST: createNumbers & getDuplicate ===\n");
unsigned int len = 20;
unsigned int *arr = createNumbers(len);
if (!arr)
{
printf("FAILED: createNumbers returned NULL\n");
return 1;
}
printf("Array created: ");
for (unsigned int i = 0; i < len; i++)
printf("%u ", arr[i]);
printf("\n");
unsigned int dup = getDuplicate(arr, len);
if (dup == 0)
{
printf("FAILED: getDuplicate returned 0 (no duplicate found)\n");
free(arr);
return 1;
}
// Count occurrences manually as safety check
unsigned int count = 0;
for (unsigned int i = 0; i < len; i++)
if (arr[i] == dup)
count++;
if (count != 2)
{
printf("FAILED: duplicate=%u occurs %u times (expected 2)\n", dup, count);
free(arr);
return 1;
}
printf("SUCCESS: duplicate number is %u and appears exactly twice.\n", dup);
free(arr);
return 0;
}

BIN
test_numbers.exe Normal file

Binary file not shown.

41
test_stack.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
int main() {
StackNode *stack = NULL;
// Einige Integer dynamisch alloziieren
int *a = malloc(sizeof(int));
int *b = malloc(sizeof(int));
int *c = malloc(sizeof(int));
*a = 10; *b = 20; *c = 30;
stack = push(stack, a);
stack = push(stack, b);
stack = push(stack, c);
// Test top()
printf("Top = %d (expected 30)\n", *(int *)top(stack));
// pop()
stack = pop(stack); // removed 30
free(c); // data gehört Benutzer!
printf("Top = %d (expected 20)\n", *(int *)top(stack));
stack = pop(stack); free(b); // removed 20
stack = pop(stack); free(a); // removed 10
// stack should now be empty
if (stack == NULL) {
printf("Stack empty ok\n");
} else {
printf("Error: stack not empty!\n");
}
// Cleanup just in case
clearStack(stack);
return 0;
}

BIN
test_stack.exe Normal file

Binary file not shown.

BIN
timer.o Normal file

Binary file not shown.