Compare commits

...
8 Commits
Author SHA1 Message Date
fonkou 526f1c3884 add makefile 2025-12-02 15:58:36 +01:00
fonkou 941374cbc2 add testStack.c and test_number.c 2025-12-02 15:53:19 +01:00
fonkou 9f0191845d add testStack.c and test_number.c 2025-12-02 15:48:32 +01:00
fonkou d264a7513e add some files 2025-12-02 15:23:22 +01:00
fonkou 2801e4b709 fix bintree.c and numbers.c 2025-12-02 01:55:08 +01:00
fonkoukamtewi101876 43a953eaa6 Merge pull request 'set-stack-push-function' (#2) from set-stack-push-function into main
Reviewed-on: #2
2025-12-02 00:45:19 +00:00
fonkou c2955be947 fix stac.c 2025-12-02 01:42:34 +01:00
fonkou 2c8974b6c6 add typdef StackNode 2025-11-25 16:57:33 +01:00
9 changed files with 368 additions and 47 deletions

No files matched your search

+70 -3
View File
@@ -10,27 +10,94 @@
// 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 (!root) {
// allocate new node
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) {
// duplicate
if (isDuplicate) *isDuplicate = 1;
return root; // do not insert duplicate
}
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)
{
static StackNode *stack = NULL;
// New tree → reset stack and push left path
if (root != NULL) {
clearStack(stack);
stack = NULL;
TreeNode *curr = root;
while (curr) {
stack = push(stack, curr);
curr = curr->left;
}
}
// No tree / finished
if (!stack) return NULL;
// Top node
TreeNode *node = top(stack);
stack = pop(stack);
// After returning node, push its right subtree (all left nodes)
TreeNode *curr = node->right;
while (curr) {
stack = push(stack, curr);
curr = curr->left;
}
return node->data;
}
// Releases all memory resources (including data copies).
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.
unsigned int treeSize(const TreeNode *root)
{
if (!root) return 0;
return 1 + treeSize(root->left) + treeSize(root->right);
}
+1
View File
@@ -0,0 +1 @@
kamte;2990
+32 -19
View File
@@ -1,8 +1,12 @@
# --------------------------
# Compiler & Flags
# --------------------------
CC = gcc
FLAGS = -g -Wall -lm
FLAGS = -g -Wall
ifeq ($(OS),Windows_NT)
include makefile_windows.variables
RM = del /f
else
UNAME = $(shell uname)
ifeq ($(UNAME),Linux)
@@ -10,40 +14,49 @@ else
else
include makefile_mac.variables
endif
RM = rm -f
endif
raylibfolder = ./raylib
unityfolder = ./unity
# --------------------------
# Initiales Programm bauen (zum ausprobieren)
# Objects du programme
# --------------------------
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
# --------------------------
# Cible principale
# --------------------------
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o $@
%.o : %.c
$(CC) $(FLAGS) -c $< -o $@
# --------------------------
# Programme initial
# --------------------------
doble_initial:
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
# --------------------------
# Selbst implementiertes Programm bauen
# Tests unitaires
# --------------------------
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble
# Compile testStack.c en un exécutable testStack
unitTests: testStack.o stack.o
$(CC) $(FLAGS) testStack.o stack.o -o testStack
@echo "----------------------------"
@echo "Running unit tests..."
./testStack
@echo "----------------------------"
$(program_obj_filesobj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
# Unit Tests
# --------------------------
unitTests:
echo "needs to be implemented"
testStack.o: testStack.c
$(CC) $(FLAGS) -c testStack.c -o testStack.o
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble
else
rm -f *.o doble
endif
$(RM) *.o doble testStack doble_initial
+89 -3
View File
@@ -1,9 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
@@ -14,13 +13,100 @@
// 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.
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
// Returns NULL on errors.
unsigned int *createNumbers(unsigned int len)
{
if (len < 2) return NULL;
// Allocate memory for the array
unsigned int *numbers = malloc(len * sizeof(unsigned int));
if (!numbers) return NULL;
// Initialize random number generator
srand((unsigned int)time(NULL));
// We need to ensure len-1 unique numbers in range [1, 2*len]
unsigned int maxValue = 2 * len;
unsigned int uniqueCount = len - 1; // We'll generate len-1 unique values
// Generate unique numbers using a simple linear search approach
for (unsigned int i = 0; i < uniqueCount; i++) {
int isUnique;
unsigned int candidate;
// Keep generating until we find a unique number
do {
candidate = (rand() % maxValue) + 1; // Random number in [1, 2*len]
isUnique = 1;
// Check if candidate already exists in our array so far
for (unsigned int j = 0; j < i; j++) {
if (numbers[j] == candidate) {
isUnique = 0;
break;
}
}
} while (!isUnique);
numbers[i] = candidate;
}
// Now we have len-1 unique numbers. Duplicate one of them.
// Choose a random index from the unique numbers
unsigned int duplicateIndex = rand() % uniqueCount;
unsigned int duplicateValue = numbers[duplicateIndex];
// Add the duplicate at the last position
numbers[len - 1] = duplicateValue;
// Shuffle the entire array to randomize the position of the duplicate
for (unsigned int i = 0; i < len; i++) {
unsigned int swapIndex = rand() % len;
// Swap numbers[i] and numbers[swapIndex]
unsigned int temp = numbers[i];
numbers[i] = numbers[swapIndex];
numbers[swapIndex] = temp;
}
return numbers;
}
// 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)
{
if (!numbers || len < 2) return 0;
}
// Create a copy of the array since we need to sort it
unsigned int *copy = malloc(len * sizeof(unsigned int));
if (!copy) return 0;
memcpy(copy, numbers, len * sizeof(unsigned int));
// Simple bubble sort implementation (no external function dependencies)
for (unsigned int i = 0; i < len - 1; i++) {
for (unsigned int j = 0; j < len - i - 1; j++) {
if (copy[j] > copy[j + 1]) {
// Swap if out of order
unsigned int temp = copy[j];
copy[j] = copy[j + 1];
copy[j + 1] = temp;
}
}
}
// Now find the duplicate by checking adjacent elements
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;
}
+1
View File
@@ -4,6 +4,7 @@
// 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);
// Returns only the only number in numbers which is present twice. Returns zero on errors.
+31 -21
View File
@@ -1,33 +1,43 @@
#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. */
typedef struct Stack_node {
void *data;
struct Stack_node *next;
} StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
// Pushes data onto the stack.
// Returns the new top of the stack.
StackNode *push(StackNode *stack, void *data) {
StackNode *node = malloc(sizeof(StackNode));
if (!node) return stack; // allocation failed → leave unchanged
node->data = data;
node->next = stack;
return node; // new top element
}
// 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)
{
// Deletes the top element and returns the new stack top.
// Caller must free the *data* itself.
StackNode *pop(StackNode *stack) {
if (!stack) return NULL;
StackNode *next = stack->next;
free(stack); // free only the node, NOT the data
return next;
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
// Returns the data at the top of the stack.
void *top(StackNode *stack) {
if (!stack) return NULL;
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
}
// Clears entire stack (but does NOT free the data).
void clearStack(StackNode *stack) {
while (stack) {
StackNode *next = stack->next;
free(stack);
stack = next;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ This means that with each new element all other elements are pushed deeper into
The latest element is taken from the stack. */
#include <stdlib.h>
typedef struct Stack_node StackNode;
//TODO: passenden Datentyp als struct anlegen
// Pushes data as pointer onto the stack.
+70
View File
@@ -0,0 +1,70 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "stack.h"
// Helper: create int on heap
static int *make_int(int value) {
int *p = malloc(sizeof(int));
if (!p) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
*p = value;
return p;
}
int main(void) {
printf("Running stack unit tests...\n");
StackNode *stack = NULL;
// --- Test 1: push() on empty stack ---
int *a = make_int(10);
stack = push(stack, a);
assert(stack != NULL);
assert(top(stack) == a);
assert(*(int*)top(stack) == 10);
// --- Test 2: push() on non-empty stack ---
int *b = make_int(20);
stack = push(stack, b);
assert(top(stack) == b);
assert(*(int*)top(stack) == 20);
// --- Test 3: pop() returns previous element ---
stack = pop(stack); // removes 20
assert(top(stack) == a);
assert(*(int*)top(stack) == 10);
// --- Test 4: pop() on single element returns NULL ---
stack = pop(stack); // removes 10
assert(stack == NULL);
// --- Test 5: pop() on empty stack returns NULL ---
stack = pop(stack);
assert(stack == NULL);
// --- Test 6: clearStack() empties a multi-element stack ---
int *c = make_int(1);
int *d = make_int(2);
int *e = make_int(3);
stack = push(stack, c);
stack = push(stack, d);
stack = push(stack, e);
clearStack(stack);
stack = NULL;
// free allocated ints
free(a);
free(b);
free(c);
free(d);
free(e);
printf("All tests passed successfully.\n");
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "stack.h"
// Helper: create int on heap
static int *make_int(int value) {
int *p = malloc(sizeof(int));
if (!p) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
*p = value;
return p;
}
int main(void) {
printf("Running stack unit tests...\n");
StackNode *stack = NULL;
// --- Test 1: push() on empty stack ---
int *a = make_int(10);
stack = push(stack, a);
assert(stack != NULL);
assert(top(stack) == a);
assert(*(int*)top(stack) == 10);
// --- Test 2: push() on non-empty stack ---
int *b = make_int(20);
stack = push(stack, b);
assert(top(stack) == b);
assert(*(int*)top(stack) == 20);
// --- Test 3: pop() returns previous element ---
stack = pop(stack); // removes 20
assert(top(stack) == a);
assert(*(int*)top(stack) == 10);
// --- Test 4: pop() on single element returns NULL ---
stack = pop(stack); // removes 10
assert(stack == NULL);
// --- Test 5: pop() on empty stack returns NULL ---
stack = pop(stack);
assert(stack == NULL);
// --- Test 6: clearStack() empties a multi-element stack ---
int *c = make_int(1);
int *d = make_int(2);
int *e = make_int(3);
stack = push(stack, c);
stack = push(stack, d);
stack = push(stack, e);
clearStack(stack);
// stack pointer still points to old top; we must reset manually
stack = NULL;
// no crash = success
// free remaining data
free(a);
free(b);
free(c);
free(d);
free(e);
printf("All tests passed successfully.\n");
return 0;
}