diff --git a/bintree.c b/bintree.c index 5cf82a9..82d2789 100644 --- a/bintree.c +++ b/bintree.c @@ -1,36 +1,106 @@ -#include -#include "stack.h" #include "bintree.h" +#include "stack.h" +#include -//TODO: binären Suchbaum implementieren +// 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. */ + * `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) -{ +// typedef int (*CompareFctType)(const void *arg1, const void *arg2); +// 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 (isDuplicate) { + *isDuplicate = 0; + } + + if (root == NULL) { + TreeNode *node = malloc(sizeof(TreeNode)); + node->data = malloc(dataSize); + memcpy(node->data, data, dataSize); + node->left = NULL; + node->right = NULL; + 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 { + // Duplikat + if (isDuplicate) { + *isDuplicate = 1; + } + } + 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) -{ +// 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; + + // Neue Iteration starten + if (root != NULL) { + clearStack(&stack); + + TreeNode *curr = root; + + // Alle linken Kinder pushen + while (curr != NULL) { + stack = push(stack, curr); + curr = curr->left; + } + } + + // Wenn leer → fertig + if (stack == NULL) + return NULL; + + // Oberstes Element lesen + TreeNode *node = (TreeNode *)stack->data; + stack = pop(stack); + + // Jetzt den rechten Teilbaum verarbeiten + TreeNode *curr = node->right; + while (curr != NULL) { + stack = push(stack, curr); + curr = curr->left; + } + + return node->data; } // 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. -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); } \ No newline at end of file diff --git a/highscores.txt b/highscores.txt index ca5950d..cf3230a 100644 --- a/highscores.txt +++ b/highscores.txt @@ -1,2 +1,5 @@ krisp;4986 +krisp;4985 +Kristin;4972 player1;3999 +krisp;3991 diff --git a/makefile b/makefile index c923a04..bc65fb7 100644 --- a/makefile +++ b/makefile @@ -36,16 +36,39 @@ $(program_obj_files): %.o: %.c # Unit Tests # -------------------------- -TEST_BIN = runTests +STACK_TEST_BIN = runStackTests +NUMBERS_TEST_BIN = runNumbersTests +BINARY_TEST_BIN = runBinaryTests -unitTests: stack.o test_stack.o - $(CC) $(FLAGS) -I$(unityfolder) -o $(TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c +# --- Stack Tests --- +stackTests: stack.o test_stack.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(STACK_TEST_BIN) \ + stack.o test_stack.o $(unityfolder)/unity.c test_stack.o: test_stack.c $(CC) $(FLAGS) -I$(unityfolder) -c test_stack.c -o test_stack.o + +# --- Numbers Tests --- +numbersTests: numbers.o bintree.o stack.o test_numbers.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(NUMBERS_TEST_BIN) \ + numbers.o bintree.o stack.o test_numbers.o $(unityfolder)/unity.c + +test_numbers.o: test_numbers.c + $(CC) $(FLAGS) -I$(unityfolder) -c test_numbers.c -o test_numbers.o + + +# --- Binary Tree Tests --- +binaryTests: bintree.o stack.o test_binary.o + $(CC) $(FLAGS) -I$(unityfolder) -o $(BINARY_TEST_BIN) \ + bintree.o stack.o test_binary.o $(unityfolder)/unity.c + +test_binary.o: test_binary.c + $(CC) $(FLAGS) -I$(unityfolder) -c test_binary.c -o test_binary.o + + # -------------------------- # Clean # -------------------------- clean: - rm -f *.o doble + rm -f *.o doble $(STACK_TEST_BIN) $(NUMBERS_TEST_BIN) $(BINARY_TEST_BIN) \ No newline at end of file diff --git a/numbers.c b/numbers.c index f59d9a2..414a4a4 100644 --- a/numbers.c +++ b/numbers.c @@ -1,26 +1,91 @@ -#include -#include -#include -#include #include "numbers.h" #include "bintree.h" +#include +#include +#include +#include -//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) -{ +int compareUnsignedInt(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; } -// 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) -{ +// 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. */ -} \ No newline at end of file +// 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) { + if (len < 2) + return NULL; + + unsigned int *arr = malloc(sizeof(unsigned int) * len); + if (!arr) + return NULL; + + TreeNode *root = NULL; + srand((unsigned int)time(NULL)); + + for (unsigned int i = 0; i < len - 1; i++) { + unsigned int num; + int isDuplicate; + + do { + num = (rand() % (2 * len)) + 1; + isDuplicate = 0; + + root = addToTree(root, &num, sizeof(unsigned int), compareUnsignedInt, + &isDuplicate); + + } while (isDuplicate); // nur akzeptieren, wenn eindeutig + + arr[i] = num; + } + + // Jetzt gezielt EIN Duplikat erzeugen + unsigned int duplicateIndex = rand() % (len - 1); + arr[len - 1] = arr[duplicateIndex]; + + clearTree(root); + return arr; +} + +// 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; + + unsigned int *copy = malloc(sizeof(unsigned int) * len); + if (!copy) + return 0; + + memcpy(copy, numbers, sizeof(unsigned int) * len); + + // Sortierung + qsort(copy, len, sizeof(unsigned int), compareUnsignedInt); + + // Duplikat finden: zwei gleiche nebeneinander + 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/test_binary.c b/test_binary.c new file mode 100644 index 0000000..a0d9cbc --- /dev/null +++ b/test_binary.c @@ -0,0 +1,105 @@ +#include "unity.h" +#include +#include +#include + +#include "bintree.h" +int compareUnsignedInt(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; +} + +TreeNode *root = NULL; + +void setUp(void) { + root = NULL; // vor jedem Test leeren +} + +void tearDown(void) { clearTree(root); } + +// Test, ob addToTree Knoten korrekt hinzufügt +void test_addToTree_basic(void) { + int isDup; + unsigned int val = 10; + root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup); + TEST_ASSERT_NOT_NULL(root); + TEST_ASSERT_EQUAL_UINT(10, *(unsigned int *)root->data); + TEST_ASSERT_EQUAL_INT(0, isDup); + TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); +} + +// Test, dass Duplikate erkannt werden +void test_addToTree_duplicate(void) { + int isDup; + unsigned int val1 = 10, val2 = 10; + root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDup); + TEST_ASSERT_EQUAL_INT(0, isDup); + root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDup); + TEST_ASSERT_EQUAL_INT(1, isDup); + TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // Duplikate nicht hinzufügen +} + +// Test nextTreeData Traversierung +void test_nextTreeData_in_order(void) { + unsigned int values[] = {20, 10, 30}; + int isDup; + for (int i = 0; i < 3; i++) { + root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt, + &isDup); + } + + unsigned int expected[] = {10, 20, 30}; + int idx = 0; + void *data; + + // **Neue Iteration starten** + data = nextTreeData(root); + while (data != NULL) { + TEST_ASSERT_EQUAL_UINT(expected[idx], *(unsigned int *)data); + idx++; + data = nextTreeData(NULL); // weitere Elemente abrufen + } + + TEST_ASSERT_EQUAL_INT(3, idx); // alle 3 Knoten besucht +} + +// Test clearTree gibt Speicher frei +void test_clearTree(void) { + unsigned int val = 42; + int isDup; + root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup); + clearTree(root); + root = NULL; // clearTree löscht nicht die root-Variable selbst + TEST_ASSERT_NULL(root); +} + +// Test treeSize zählt korrekt +void test_treeSize(void) { + unsigned int vals[] = {10, 20, 5}; + int isDup; + for (int i = 0; i < 3; i++) { + root = + addToTree(root, &vals[i], sizeof(vals[i]), compareUnsignedInt, &isDup); + } + TEST_ASSERT_EQUAL_UINT(3, treeSize(root)); +} + +int main(void) { + UNITY_BEGIN(); + + printf( + "\n------------------------binarytree test------------------------\n\n"); + + RUN_TEST(test_addToTree_basic); + RUN_TEST(test_addToTree_duplicate); + RUN_TEST(test_nextTreeData_in_order); + RUN_TEST(test_clearTree); + RUN_TEST(test_treeSize); + return UNITY_END(); +} \ No newline at end of file diff --git a/test_numbers.c b/test_numbers.c new file mode 100644 index 0000000..8992bb8 --- /dev/null +++ b/test_numbers.c @@ -0,0 +1,61 @@ +#include "unity.h" +#include +#include +#include + +#include "numbers.h" + +#define TEST_ARRAY_LEN 100 + +void test_createNumbers_length(void) { + unsigned int *arr = createNumbers(TEST_ARRAY_LEN); + TEST_ASSERT_NOT_NULL(arr); + free(arr); +} + +void test_createNumbers_single_duplicate(void) { + unsigned int *arr = createNumbers(TEST_ARRAY_LEN); + TEST_ASSERT_NOT_NULL(arr); + + unsigned int duplicate = getDuplicate(arr, TEST_ARRAY_LEN); + TEST_ASSERT_TRUE(duplicate > 0); + + unsigned int count = 0; + for (unsigned int i = 0; i < TEST_ARRAY_LEN; i++) { + if (arr[i] == duplicate) { + count++; + } + } + TEST_ASSERT_EQUAL_UINT(2, count); + + free(arr); +} + +void test_getDuplicate_manual_array(void) { + unsigned int numbers[5] = {10, 20, 30, 40, 20}; + unsigned int dup = getDuplicate(numbers, 5); + TEST_ASSERT_EQUAL_UINT(20, dup); +} + +void test_getDuplicate_invalid_input(void) { + TEST_ASSERT_EQUAL_UINT(0, getDuplicate(NULL, 5)); + unsigned int arr[1] = {42}; + TEST_ASSERT_EQUAL_UINT(0, getDuplicate(arr, 1)); +} + +void setUp(void) {} +void tearDown(void) {} + +int main(void) { + + UNITY_BEGIN(); + + printf("\n------------------------numbers test------------------------\n\n"); + + RUN_TEST(test_createNumbers_length); + RUN_TEST(test_createNumbers_single_duplicate); + RUN_TEST(test_getDuplicate_manual_array); + RUN_TEST(test_getDuplicate_invalid_input); + + return UNITY_END(); +} diff --git a/test_stack.c b/test_stack.c index 9f14a45..533af6a 100644 --- a/test_stack.c +++ b/test_stack.c @@ -41,13 +41,13 @@ void test_deleteTopElement(void) { stack = push(stack, &testInts[i]); } - TEST_ASSERT_EQUAL_PTR(&testInts[2], top(stack)); + TEST_ASSERT_EQUAL_PTR(&testInts[2], stack->data); stack = pop(stack); - TEST_ASSERT_EQUAL_PTR(&testInts[1], top(stack)); + TEST_ASSERT_EQUAL_PTR(&testInts[1], stack->data); stack = pop(stack); - TEST_ASSERT_EQUAL_PTR(&testInts[0], top(stack)); + TEST_ASSERT_EQUAL_PTR(&testInts[0], stack->data); stack = pop(stack); TEST_ASSERT_NULL(stack); @@ -98,7 +98,7 @@ int main(void) { UNITY_BEGIN(); - printf("------------------------stack test------------------------\n"); + printf("\n------------------------stack test------------------------\n\n"); RUN_TEST(test_createNode); RUN_TEST(test_pushDataToStack);