Fertig
This commit is contained in:
parent
c325131503
commit
d56c77d77a
113
bintree.c
113
bintree.c
@ -2,35 +2,126 @@
|
|||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
#include "bintree.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. */
|
|
||||||
|
|
||||||
// Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates
|
// 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).
|
// 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 (data == NULL || compareFct == NULL)
|
||||||
|
return root;
|
||||||
|
|
||||||
|
if (root == NULL)
|
||||||
|
{
|
||||||
|
// neuer Knoten
|
||||||
|
TreeNode *node = malloc(sizeof(TreeNode));
|
||||||
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// Element bereits vorhanden
|
||||||
|
if (isDuplicate != NULL)
|
||||||
|
{
|
||||||
|
*isDuplicate = 1;
|
||||||
|
// Duplikate werden ignoriert
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Duplikate dürfen eingefügt werden -> wir hängen sie z.B. links an
|
||||||
|
root->left = addToTree(root->left, data, dataSize, compareFct, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// Interner Stack für die Traversierung (strtok-ähnliches Verhalten)
|
||||||
// Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element,
|
static StackNode *iterStack = NULL;
|
||||||
// push the top node and push all its left nodes.
|
|
||||||
|
// Hilfsfunktion: legt ab start alle linken Knoten auf den Stack
|
||||||
|
static void pushLeftPath(TreeNode *start)
|
||||||
|
{
|
||||||
|
while (start != NULL)
|
||||||
|
{
|
||||||
|
iterStack = push(iterStack, start);
|
||||||
|
start = start->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
void *nextTreeData(TreeNode *root)
|
||||||
{
|
{
|
||||||
|
if (root != NULL)
|
||||||
|
{
|
||||||
|
// neue Traversierung starten: alten Stack aufräumen
|
||||||
|
if (iterStack != NULL)
|
||||||
|
{
|
||||||
|
clearStack(iterStack);
|
||||||
|
iterStack = NULL;
|
||||||
|
}
|
||||||
|
pushLeftPath(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterStack == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Nächsten Knoten holen
|
||||||
|
TreeNode *node = (TreeNode *)top(iterStack);
|
||||||
|
iterStack = pop(iterStack);
|
||||||
|
|
||||||
|
// rechten Teilbaum dieses Knotens auf den Stack bringen
|
||||||
|
if (node->right != NULL)
|
||||||
|
pushLeftPath(node->right);
|
||||||
|
|
||||||
|
return node->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Releases all memory resources (including data copies).
|
// Releases all memory resources (including data copies).
|
||||||
void clearTree(TreeNode *root)
|
void clearTree(TreeNode *root)
|
||||||
{
|
{
|
||||||
|
if (root == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearTree(root->left);
|
||||||
|
clearTree(root->right);
|
||||||
|
|
||||||
|
free(root->data);
|
||||||
|
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 1u + treeSize(root->left) + treeSize(root->right);
|
||||||
|
}
|
||||||
|
|||||||
BIN
doble_initial.exe
Normal file
BIN
doble_initial.exe
Normal file
Binary file not shown.
BIN
highscore.o
Normal file
BIN
highscore.o
Normal file
Binary file not shown.
@ -1 +1,3 @@
|
|||||||
|
Kilian;9927
|
||||||
|
Kilian;4975
|
||||||
player1;3999
|
player1;3999
|
||||||
|
|||||||
70
makefile
70
makefile
@ -1,4 +1,4 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
FLAGS = -g -Wall -lm
|
FLAGS = -g -Wall -lm
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@ -13,10 +13,18 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
raylibfolder = ./raylib
|
raylibfolder = ./raylib
|
||||||
unityfolder = ./unity
|
unityfolder = ./unity
|
||||||
|
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Initiales Programm bauen (zum ausprobieren)
|
# Phony Targets
|
||||||
|
# --------------------------
|
||||||
|
.PHONY: all doble doble_initial unitTests test_stack test_numbers clean vorbereitungen prepare
|
||||||
|
|
||||||
|
# Standard-Target
|
||||||
|
all: doble
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Initiales Programm bauen (zum Ausprobieren)
|
||||||
# --------------------------
|
# --------------------------
|
||||||
doble_initial:
|
doble_initial:
|
||||||
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
||||||
@ -26,24 +34,66 @@ doble_initial:
|
|||||||
# --------------------------
|
# --------------------------
|
||||||
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
|
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
|
$(CC) $(FLAGS) $^ -o doble
|
||||||
|
|
||||||
$(program_obj_filesobj_files): %.o: %.c
|
# Generische Regel zum Bauen von .o aus .c
|
||||||
$(CC) -c $(FLAGS) $^ -o $@
|
%.o: %.c
|
||||||
|
$(CC) $(FLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
# Abhängigkeiten (optional, aber hilfreich für inkrementelles Bauen)
|
||||||
|
main.o: main.c numbers.h stack.h bintree.h timer.h highscore.h
|
||||||
|
numbers.o: numbers.c numbers.h bintree.h
|
||||||
|
bintree.o: bintree.c bintree.h stack.h
|
||||||
|
stack.o: stack.c stack.h
|
||||||
|
timer.o: timer.c timer.h
|
||||||
|
highscore.o: highscore.c highscore.h
|
||||||
|
|
||||||
|
test_stack.o: test_stack.c stack.h
|
||||||
|
test_numbers.o: test_numbers.c numbers.h bintree.h stack.h
|
||||||
|
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Unit Tests
|
# Unit Tests
|
||||||
# --------------------------
|
# --------------------------
|
||||||
unitTests:
|
test_stack: test_stack.o stack.o
|
||||||
echo "needs to be implemented"
|
$(CC) $(FLAGS) $^ -o test_stack
|
||||||
|
|
||||||
|
test_numbers: test_numbers.o numbers.o stack.o bintree.o
|
||||||
|
$(CC) $(FLAGS) $^ -o test_numbers
|
||||||
|
|
||||||
|
unitTests: test_stack test_numbers
|
||||||
|
./test_stack
|
||||||
|
./test_numbers
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# Vorbereitungen zum Bauen des Programms
|
||||||
|
# --------------------------
|
||||||
|
vorbereitungen:
|
||||||
|
@echo "== Vorbereitungen zum Bauen des Programms =="
|
||||||
|
@echo "Prüfe benötigte Dateien..."
|
||||||
|
@test -f numbers.c || (echo "FEHLT: numbers.c" && exit 1)
|
||||||
|
@test -f numbers.h || (echo "FEHLT: numbers.h" && exit 1)
|
||||||
|
@test -f bintree.c || (echo "FEHLT: bintree.c" && exit 1)
|
||||||
|
@test -f bintree.h || (echo "FEHLT: bintree.h" && exit 1)
|
||||||
|
@test -f stack.c || (echo "FEHLT: stack.c" && exit 1)
|
||||||
|
@test -f stack.h || (echo "FEHLT: stack.h" && exit 1)
|
||||||
|
@test -f timer.c || (echo "FEHLT: timer.c" && exit 1)
|
||||||
|
@test -f timer.h || (echo "FEHLT: timer.h" && exit 1)
|
||||||
|
@test -f highscore.c || (echo "FEHLT: highscore.c" && exit 1)
|
||||||
|
@test -f highscore.h || (echo "FEHLT: highscore.h" && exit 1)
|
||||||
|
@test -f main.c || (echo "FEHLT: main.c" && exit 1)
|
||||||
|
@echo "Alle Dateien vorhanden."
|
||||||
|
@echo "Vorbereitung abgeschlossen!"
|
||||||
|
|
||||||
|
# englischer Alias
|
||||||
|
prepare: vorbereitungen
|
||||||
|
|
||||||
# --------------------------
|
# --------------------------
|
||||||
# Clean
|
# Clean
|
||||||
# --------------------------
|
# --------------------------
|
||||||
clean:
|
clean:
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
del /f *.o doble
|
del /f *.o doble doble_initial test_stack test_numbers
|
||||||
else
|
else
|
||||||
rm -f *.o doble
|
rm -f *.o doble doble_initial test_stack test_numbers
|
||||||
endif
|
endif
|
||||||
99
numbers.c
99
numbers.c
@ -5,22 +5,109 @@
|
|||||||
#include "numbers.h"
|
#include "numbers.h"
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
//TODO: getDuplicate und createNumbers implementieren
|
// Hilfsfunktion für qsort und den Binärbaum: Vergleich von unsigned int
|
||||||
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
|
static int compareUnsignedInt(const void *a, const void *b)
|
||||||
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
|
{
|
||||||
* Duplizieren eines zufälligen Eintrags im Array.
|
const unsigned int *ua = (const unsigned int *)a;
|
||||||
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
|
const unsigned int *ub = (const unsigned int *)b;
|
||||||
|
|
||||||
|
if (*ua < *ub)
|
||||||
|
return -1;
|
||||||
|
else if (*ua > *ub)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
|
// 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
|
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
|
||||||
// creating random numbers.
|
// creating random numbers.
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int *createNumbers(unsigned int len)
|
||||||
{
|
{
|
||||||
|
if (len < 2)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned int *numbers = malloc(len * sizeof(unsigned int));
|
||||||
|
if (numbers == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Zufall initialisieren
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
|
||||||
|
TreeNode *root = NULL;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
// len-1 verschiedene Zufallszahlen im Bereich [1, 2*len] erzeugen
|
||||||
|
while (i < len - 1)
|
||||||
|
{
|
||||||
|
unsigned int candidate = (unsigned int)(rand() % (2 * len)) + 1;
|
||||||
|
int isDuplicate = 0;
|
||||||
|
|
||||||
|
TreeNode *newRoot = addToTree(root, &candidate, sizeof(unsigned int),
|
||||||
|
compareUnsignedInt, &isDuplicate);
|
||||||
|
if (newRoot == NULL && root == NULL)
|
||||||
|
{
|
||||||
|
// Speicherfehler beim ersten Einfügen
|
||||||
|
clearTree(root);
|
||||||
|
free(numbers);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
root = newRoot;
|
||||||
|
|
||||||
|
if (!isDuplicate)
|
||||||
|
{
|
||||||
|
numbers[i] = candidate;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
// bei Duplikat wird einfach eine neue Zufallszahl generiert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Einen zufälligen Eintrag aus den ersten len-1 duplizieren
|
||||||
|
unsigned int duplicateIndex = (unsigned int)(rand() % (len - 1));
|
||||||
|
numbers[len - 1] = numbers[duplicateIndex];
|
||||||
|
|
||||||
|
// Baum wird nicht mehr benötigt
|
||||||
|
clearTree(root);
|
||||||
|
|
||||||
|
// Das Array durchmischen (Fisher-Yates-Shuffle), damit das Duplikat an zufälliger Position steht
|
||||||
|
for (unsigned int j = len - 1; j > 0; --j)
|
||||||
|
{
|
||||||
|
unsigned int k = (unsigned int)(rand() % (j + 1));
|
||||||
|
unsigned int tmp = numbers[j];
|
||||||
|
numbers[j] = numbers[k];
|
||||||
|
numbers[k] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
// 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)
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
||||||
{
|
{
|
||||||
|
if (numbers == NULL || len < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
// Kopie des Arrays anlegen, da qsort in-place sortiert
|
||||||
|
unsigned int *copy = malloc(len * sizeof(unsigned int));
|
||||||
|
if (copy == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(copy, numbers, len * sizeof(unsigned int));
|
||||||
|
|
||||||
|
// Sortieren mit qsort
|
||||||
|
qsort(copy, len, sizeof(unsigned int), compareUnsignedInt);
|
||||||
|
|
||||||
|
// Benachbarte Elemente vergleichen, um das Duplikat zu finden
|
||||||
|
unsigned int duplicate = 0;
|
||||||
|
for (unsigned int i = 1; i < len; ++i)
|
||||||
|
{
|
||||||
|
if (copy[i] == copy[i - 1])
|
||||||
|
{
|
||||||
|
duplicate = copy[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(copy);
|
||||||
|
return duplicate; // 0 falls kein Duplikat gefunden (Fehlerfall)
|
||||||
|
}
|
||||||
|
|||||||
29
stack.c
29
stack.c
@ -1,33 +1,46 @@
|
|||||||
#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 *node = (StackNode *)malloc(sizeof(StackNode));
|
||||||
|
if (node == NULL)
|
||||||
|
return stack; // keine Änderung bei Speicherfehler
|
||||||
|
|
||||||
|
node->data = data;
|
||||||
|
node->next = stack;
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
8
stack.h
8
stack.h
@ -7,7 +7,12 @@ The latest element is taken from the stack. */
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//TODO: passenden Datentyp als struct anlegen
|
// einfacher verketteter Stack
|
||||||
|
typedef struct StackNode
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
struct StackNode *next;
|
||||||
|
} 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);
|
||||||
@ -23,3 +28,4 @@ void *top(StackNode *stack);
|
|||||||
void clearStack(StackNode *stack);
|
void clearStack(StackNode *stack);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
121
test_numbers.c
Normal file
121
test_numbers.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "numbers.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unit-Tests für createNumbers und getDuplicate:
|
||||||
|
* - createNumbers liefert ein gültiges Array
|
||||||
|
* - alle Zahlen liegen im Bereich [1, 2*len]
|
||||||
|
* - genau eine Zahl kommt doppelt vor
|
||||||
|
* - getDuplicate findet genau diese doppelte Zahl
|
||||||
|
* - Fehlerfälle (NULL-Pointer, zu kleine Länge)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void check_numbers_array(unsigned int *numbers, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int maxValue = 2 * len;
|
||||||
|
unsigned int *counts;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int duplicatesCount = 0;
|
||||||
|
|
||||||
|
assert(numbers != NULL);
|
||||||
|
|
||||||
|
counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
|
||||||
|
assert(counts != NULL);
|
||||||
|
|
||||||
|
// Werte zählen und Bereich prüfen
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
unsigned int v = numbers[i];
|
||||||
|
assert(v >= 1 && v <= maxValue);
|
||||||
|
counts[v]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfen: genau eine Zahl kommt zweimal vor, alle anderen höchstens einmal
|
||||||
|
for (i = 1; i <= maxValue; ++i)
|
||||||
|
{
|
||||||
|
if (counts[i] == 2)
|
||||||
|
duplicatesCount++;
|
||||||
|
else
|
||||||
|
assert(counts[i] == 0 || counts[i] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(duplicatesCount == 1);
|
||||||
|
|
||||||
|
free(counts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_createNumbers_and_getDuplicate(unsigned int len)
|
||||||
|
{
|
||||||
|
printf("test_createNumbers_and_getDuplicate(len=%u)...\n", len);
|
||||||
|
|
||||||
|
unsigned int *numbers = createNumbers(len);
|
||||||
|
assert(numbers != NULL);
|
||||||
|
|
||||||
|
// Arraystruktur überprüfen
|
||||||
|
check_numbers_array(numbers, len);
|
||||||
|
|
||||||
|
// Nochmal zählen, um das Duplikat zu kennen
|
||||||
|
unsigned int maxValue = 2 * len;
|
||||||
|
unsigned int *counts = (unsigned int *)calloc(maxValue + 1, sizeof(unsigned int));
|
||||||
|
assert(counts != NULL);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
unsigned int v = numbers[i];
|
||||||
|
counts[v]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int expectedDuplicate = 0;
|
||||||
|
for (unsigned int v = 1; v <= maxValue; ++v)
|
||||||
|
{
|
||||||
|
if (counts[v] == 2)
|
||||||
|
{
|
||||||
|
expectedDuplicate = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(expectedDuplicate != 0);
|
||||||
|
|
||||||
|
// getDuplicate testen
|
||||||
|
unsigned int found = getDuplicate(numbers, len);
|
||||||
|
assert(found == expectedDuplicate);
|
||||||
|
|
||||||
|
free(counts);
|
||||||
|
free(numbers);
|
||||||
|
|
||||||
|
printf("...OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getDuplicate_error_cases(void)
|
||||||
|
{
|
||||||
|
printf("test_getDuplicate_error_cases...\n");
|
||||||
|
|
||||||
|
// NULL-Array
|
||||||
|
unsigned int dup = getDuplicate(NULL, 10);
|
||||||
|
assert(dup == 0);
|
||||||
|
|
||||||
|
// Länge < 2
|
||||||
|
unsigned int dummy[1] = {42};
|
||||||
|
dup = getDuplicate(dummy, 1);
|
||||||
|
assert(dup == 0);
|
||||||
|
|
||||||
|
printf("...OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("Running numbers unit tests...\n\n");
|
||||||
|
|
||||||
|
// Typische Testfälle mit verschiedenen Längen
|
||||||
|
test_createNumbers_and_getDuplicate(5);
|
||||||
|
test_createNumbers_and_getDuplicate(10);
|
||||||
|
test_createNumbers_and_getDuplicate(20);
|
||||||
|
|
||||||
|
// Fehlerfälle
|
||||||
|
test_getDuplicate_error_cases();
|
||||||
|
|
||||||
|
printf("\nAll numbers tests passed.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
test_numbers.exe
Normal file
BIN
test_numbers.exe
Normal file
Binary file not shown.
BIN
test_numbers.o
Normal file
BIN
test_numbers.o
Normal file
Binary file not shown.
102
test_stack.c
Normal file
102
test_stack.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Einfache Unit-Tests für den Stack:
|
||||||
|
* - push/pop: LIFO-Verhalten
|
||||||
|
* - top: richtiges Element
|
||||||
|
* - Verhalten bei leerem Stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void test_push_pop_lifo(void)
|
||||||
|
{
|
||||||
|
printf("test_push_pop_lifo...\n");
|
||||||
|
|
||||||
|
StackNode *stack = NULL;
|
||||||
|
|
||||||
|
int a = 1;
|
||||||
|
int b = 2;
|
||||||
|
int c = 3;
|
||||||
|
|
||||||
|
stack = push(stack, &a);
|
||||||
|
stack = push(stack, &b);
|
||||||
|
stack = push(stack, &c);
|
||||||
|
|
||||||
|
// LIFO: zuerst c
|
||||||
|
assert(top(stack) == &c);
|
||||||
|
stack = pop(stack);
|
||||||
|
|
||||||
|
// dann b
|
||||||
|
assert(top(stack) == &b);
|
||||||
|
stack = pop(stack);
|
||||||
|
|
||||||
|
// dann a
|
||||||
|
assert(top(stack) == &a);
|
||||||
|
stack = pop(stack);
|
||||||
|
|
||||||
|
// jetzt leer
|
||||||
|
assert(stack == NULL);
|
||||||
|
assert(top(stack) == NULL);
|
||||||
|
|
||||||
|
printf("...OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_empty_stack_operations(void)
|
||||||
|
{
|
||||||
|
printf("test_empty_stack_operations...\n");
|
||||||
|
|
||||||
|
StackNode *stack = NULL;
|
||||||
|
|
||||||
|
// pop auf leerem Stack sollte einfach NULL liefern
|
||||||
|
stack = pop(stack);
|
||||||
|
assert(stack == NULL);
|
||||||
|
|
||||||
|
// top auf leerem Stack sollte NULL liefern
|
||||||
|
assert(top(stack) == NULL);
|
||||||
|
|
||||||
|
// clearStack auf leerem Stack darf nicht crashen
|
||||||
|
clearStack(stack);
|
||||||
|
|
||||||
|
printf("...OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_clearStack(void)
|
||||||
|
{
|
||||||
|
printf("test_clearStack...\n");
|
||||||
|
|
||||||
|
StackNode *stack = NULL;
|
||||||
|
int values[10];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Wir legen 10 Elemente auf den Stack
|
||||||
|
for (i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
values[i] = i;
|
||||||
|
stack = push(stack, &values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack leeren – clearStack muss alle StackNodes freigeben
|
||||||
|
clearStack(stack);
|
||||||
|
stack = NULL; // Pointer selbst auf NULL setzen
|
||||||
|
|
||||||
|
// Auf leerem Stack dürfen die Operationen nicht crashen
|
||||||
|
assert(top(stack) == NULL);
|
||||||
|
stack = pop(stack);
|
||||||
|
assert(stack == NULL);
|
||||||
|
|
||||||
|
printf("...OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("Running stack unit tests...\n\n");
|
||||||
|
|
||||||
|
test_push_pop_lifo();
|
||||||
|
test_empty_stack_operations();
|
||||||
|
test_clearStack();
|
||||||
|
|
||||||
|
printf("\nAll stack tests passed.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
test_stack.exe
Normal file
BIN
test_stack.exe
Normal file
Binary file not shown.
BIN
test_stack.o
Normal file
BIN
test_stack.o
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user