diff --git a/.gitignore b/.gitignore index fc53910..ca403e0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ runNumbersTest.exe numbers.o .vscode/launch.json .vscode/settings.json +*.o +*.exe +runBintreeTest diff --git a/bintree.c b/bintree.c index 552c170..9a50707 100644 --- a/bintree.c +++ b/bintree.c @@ -1,7 +1,10 @@ #include +#include #include "stack.h" #include "bintree.h" +static StackNode *stack; +static TreeNode *tree = NULL; // TODO: binären Suchbaum implementieren /* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), * `clearTree`: gibt den gesamten Baum frei (rekursiv), @@ -12,8 +15,43 @@ // 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 (root == NULL) + { + TreeNode *newNode = malloc(sizeof(TreeNode)); + newNode->data = malloc(dataSize); + if (newNode->data == NULL) + { + return NULL; // Fehler + } + memcpy(newNode->data, data, dataSize); + newNode->left = NULL; + newNode->right = NULL; + return newNode; + } + int cmp = compareFct(root->data, 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 + { + if (isDuplicate != NULL) + { + *isDuplicate = 1; + return root; + } + else + { + root->left = addToTree(root->left, 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. @@ -21,7 +59,19 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFc // push the top node and push all its left nodes. void *nextTreeData(TreeNode *root) { + if (root != NULL) + { + clearStack(stack); + buildStack(root); + } + if(stack != NULL) + { + void* data = top(stack); + stack = pop(stack); + return data; + } + return NULL; } // Releases all memory resources (including data copies). @@ -31,32 +81,34 @@ void clearTree(TreeNode *root) { return; } - if (root->left != NULL) { clearTree(root->left); free(root->left); + root->left = NULL; } - else if (root->right != NULL) + if (root->right != NULL) { clearTree(root->right); free(root->right); + root->right = NULL; } - root->data = NULL; + root = NULL; } // Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root) { - int counterL, counterR = 0; - if (root->left != NULL) - { - counterL = treeSize(root->left) + 1; - } - else if (root->right != NULL) - { - counterR = treeSize(root->right) + 1; - } + return root == NULL ? 0 : treeSize(root->left) + treeSize(root->right) + 1; +} - return counterL + counterR; +void buildStack(TreeNode *root) +{ + if (root == NULL) + { + return; + } + buildStack(root->left); + stack = push(stack, root->data); + buildStack(root->right); } \ No newline at end of file diff --git a/bintree.h b/bintree.h index 25e16b2..f7be496 100644 --- a/bintree.h +++ b/bintree.h @@ -24,4 +24,6 @@ void clearTree(TreeNode *root); // Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root); +void buildStack(TreeNode *root); + #endif \ No newline at end of file diff --git a/highscore.c b/highscore.c index fe8a458..8d3ef5c 100644 --- a/highscore.c +++ b/highscore.c @@ -79,6 +79,8 @@ int addHighscore(const char *name, double timeInSeconds, unsigned int len) { HighscoreEntry entry = createHighscoreEntry(name, calculateScore(timeInSeconds, len)); highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL); + //HighscoreEntry *temp = highscoreTree->data; + //printf("%s%d\n", temp->name, temp->score); return entry.score; } diff --git a/highscores.txt b/highscores.txt index 4edd5a7..d1dcaac 100644 --- a/highscores.txt +++ b/highscores.txt @@ -1 +1,5 @@ -player1;3999 +nick;9963 +nick;9946 +simon;4965 +alex;2996 +simon;2996 diff --git a/makefile b/makefile index fdb61da..d439d9a 100644 --- a/makefile +++ b/makefile @@ -35,14 +35,20 @@ $(program_obj_filesobj_files): %.o: %.c # -------------------------- # Unit Tests # -------------------------- -unitTests: stack.o test_stack.c $(unityfolder)/unity.c +stackTests: stack.o test_stack.c $(unityfolder)/unity.c $(CC) $(FLAGS) -I$(unityfolder) -o runStackTest test_stack.c stack.o $(unityfolder)/unity.c # -------------------------- # numbers.c Tests # -------------------------- -numbersTests: numbers.o test_numbers.c $(unityfolder)/unity.c - $(CC) $(FLAGS) -I$(unityfolder) -o runNumbersTest test_numbers.c numbers.o $(unityfolder)/unity.c +numbersTests: numbers.o bintree.o stack.o test_numbers.c $(unityfolder)/unity.c + $(CC) $(FLAGS) -I$(unityfolder) -o runNumbersTest test_numbers.c numbers.o bintree.o stack.o $(unityfolder)/unity.c + +# -------------------------- +# bintree.c Tests +# -------------------------- +bintreeTests: bintree.o stack.o test_bintree.c $(unityfolder)/unity.c + $(CC) $(FLAGS) -I$(unityfolder) -o runBintreeTest test_bintree.c bintree.o stack.o $(unityfolder)/unity.c # -------------------------- # Clean diff --git a/numbers.c b/numbers.c index 41d0980..90e930a 100644 --- a/numbers.c +++ b/numbers.c @@ -14,150 +14,97 @@ // 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 checkArray(unsigned int *array, unsigned int len, unsigned int number) +void duplicateNumber(unsigned int *numbers, unsigned int len) { - int free = 1; + if (!numbers || len < 2) + return; - for (int i = 0; i < len; i++) - { - if (array[i] == number) - { - free = 0; - } - } + unsigned int numberPicked = rand() % len; // take random spot in array + unsigned int destination = rand() % len; // new spot for duplicated number - return free; + while (destination == numberPicked) // while same spot get a new one + destination = rand() % len; + + numbers[destination] = numbers[numberPicked]; +} + +/* for qsort +-1 num1 should come before num2 +0 num1 and num2 are equal +1 num1 should come after num2 +*/ +int compare(const void *num1, const void *num2) +{ + unsigned int temp1 = *(const unsigned int *)num1; + unsigned int temp2 = *(const unsigned int *)num2; + return (temp1 > temp2) - (temp1 < temp2); } unsigned int *createNumbers(unsigned int len) { - srand(time(NULL)); - unsigned int *array = (unsigned int*)malloc(len * sizeof(unsigned int)); - int randomNr, counter; + if (len < 2) + { + return NULL; + } + srand((unsigned)time(NULL)); - if(array == NULL) + TreeNode *root = NULL; + unsigned int i = 0; + + unsigned int *numbers = malloc(sizeof(unsigned int) * len); + if (!numbers) { return NULL; } - for (int i = 0; i < len; i++) + while (i < len) { - counter = 0; - do + unsigned int random = (rand() % (2 * len)) + 1; + int duplicate = 0; + + root = addToTree(root, &random, sizeof(unsigned int), compare, &duplicate); + if (!root) { - if (counter == 9) - { - return NULL; - } - - randomNr = rand() % (2 * len + 1); - counter++; - } while (!checkArray(array, i, randomNr)); - - array[i] = randomNr; - printf("%u ", array[i]); - } - - printf("\n"); - return array; -} - -void merge(unsigned int arr[], unsigned int left, unsigned int mid, unsigned int right) -{ - unsigned int i, j, k; - unsigned int n1 = mid - left + 1; - unsigned int n2 = right - mid; - - // Create temporary arrays - unsigned int leftArr[n1], rightArr[n2]; - - // Copy data to temporary arrays - for (i = 0; i < n1; i++) - leftArr[i] = arr[left + i]; - for (j = 0; j < n2; j++) - rightArr[j] = arr[mid + 1 + j]; - - // Merge the temporary arrays back into arr[left..right] - i = 0; - j = 0; - k = left; - while (i < n1 && j < n2) - { - if (leftArr[i] <= rightArr[j]) - { - arr[k] = leftArr[i]; - i++; + free(numbers); // malloc-Fehler + return NULL; } - else - { - arr[k] = rightArr[j]; - j++; - } - k++; + + if (!duplicate) + numbers[i++] = random; } - // Copy the remaining elements of leftArr[], if any - while (i < n1) - { - arr[k] = leftArr[i]; - i++; - k++; - } - - // Copy the remaining elements of rightArr[], if any - while (j < n2) - { - arr[k] = rightArr[j]; - j++; - k++; - } + duplicateNumber(numbers, len); + clearTree(root); + return numbers; } -void mergeSort(unsigned int arr[], unsigned int left, unsigned int right) -{ - if (left < right) - { - - // Calculate the midpoint - unsigned int mid = left + (right - left) / 2; - - // Sort first and second halves - mergeSort(arr, left, mid); - mergeSort(arr, mid + 1, right); - - // Merge the sorted halves - merge(arr, left, mid, right); - } -} - -// Returns only the only number in numbers which is present twice. Returns zero on errors. +// Returns 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 temp[len]; - unsigned int duplicate = 0; - - /*if(numbers == NULL || (sizeof(numbers) / sizeof(typeof(numbers)) != len)) + if (!numbers || len < 2) { - return 0;S - }*/ - - for (int i = 0; i < len; i++) - { - temp[i] = numbers[i]; + return 0; } - - // Sorting arr using mergesort - mergeSort(temp, 0, len - 1); - for (int i = 0; i < len - 1; i++) + unsigned int *copy = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (!copy) { - duplicate = temp[i]; - if (duplicate == temp[i + 1]) + return 0; + } + + memcpy(copy, numbers, len * sizeof(unsigned int)); + qsort(copy, len, sizeof(unsigned int), compare); + + 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; } \ No newline at end of file diff --git a/numbers.o b/numbers.o deleted file mode 100644 index 2b1174a..0000000 Binary files a/numbers.o and /dev/null differ diff --git a/runNumbersTest.exe b/runNumbersTest.exe deleted file mode 100644 index 8b78d8f..0000000 Binary files a/runNumbersTest.exe and /dev/null differ diff --git a/stack.c b/stack.c index 2315722..8762fa3 100644 --- a/stack.c +++ b/stack.c @@ -10,46 +10,24 @@ // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data) { - StackNode *tempNode, *newNode; - - newNode = malloc(sizeof(StackNode)); - newNode->value = *(int *)data; - newNode->next = NULL; - - if (stack == NULL) - { - stack = newNode; - return stack; - } - - tempNode = stack; - while (tempNode->next != NULL) - { - tempNode = tempNode->next; - } - tempNode->next = newNode; - - return stack; + StackNode *newNode = malloc(sizeof(StackNode)); + newNode->data = data; + newNode->next = stack; // Set the new node's next pointer to the current top of the stack. + return newNode; // Return the new node as the top of the stack. } // 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) { - StackNode *tempNode; - if (stack == NULL) { - return stack; + return NULL; // Nothing to pop if stack is empty. } - tempNode = stack; - while (tempNode->next->next != NULL) - { - tempNode = tempNode->next; - } - free(tempNode->next); - tempNode->next = NULL; + StackNode *tempNode = stack; + stack = stack->next; // Move the stack pointer to the next node. + free(tempNode); // Free the old top node. return stack; } @@ -57,35 +35,19 @@ StackNode *pop(StackNode *stack) // Returns the data of the top element. void *top(StackNode *stack) { - StackNode *tempNode; - if (stack == NULL) { - return NULL; + return NULL; // Return NULL if stack is empty. } - tempNode = stack; - while (tempNode->next != NULL) - { - tempNode = tempNode->next; - } - - return &tempNode->value; + return stack->data; // Return the value of the top node. } // Clears stack and releases all memory. void clearStack(StackNode *stack) { - StackNode *tempNode; - - if (stack == NULL) + while (stack != NULL) { - return; - } - - tempNode = stack; - while (tempNode != NULL) - { - tempNode = pop(tempNode); + stack = pop(stack); // Pop each element and free memory. } } \ No newline at end of file diff --git a/stack.h b/stack.h index d7cc86a..69ac923 100644 --- a/stack.h +++ b/stack.h @@ -9,7 +9,7 @@ The latest element is taken from the stack. */ //TODO: passenden Datentyp als struct anlegen typedef struct Node { - int value; + void *data; struct Node* next; } StackNode; diff --git a/test_bintree.c b/test_bintree.c new file mode 100644 index 0000000..b5daa3a --- /dev/null +++ b/test_bintree.c @@ -0,0 +1,80 @@ +#include +#include +#include "bintree.h" +#include "unity.h" + + +void sizeTest() +{ + TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode)); + TreeNode *node1 = (TreeNode *)malloc(sizeof(TreeNode)); + TreeNode *node2 = (TreeNode *)malloc(sizeof(TreeNode)); + + int dataRoot = 2; + int dataNode1 = 1; + int dataNode2 = 3; + + root->data = &dataRoot; + root->left = (TreeNode *)node1; + root->right = (TreeNode *)node2; + + node1->data = &dataNode1; + node1->left = NULL; + node1->right = NULL; + + node2->data = &dataNode2; + node2->left = NULL; + node2->right = NULL; + + TEST_ASSERT_EQUAL_INT(3,treeSize(root)); +} + +void clearTest() +{ + TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode)); + TreeNode *node1 = (TreeNode *)malloc(sizeof(TreeNode)); + TreeNode *node2 = (TreeNode *)malloc(sizeof(TreeNode)); + + int dataRoot = 2; + int dataNode1 = 1; + int dataNode2 = 3; + + root->data = &dataRoot; + root->left = (TreeNode *)node1; + root->right = (TreeNode *)node2; + + node1->data = &dataNode1; + node1->left = NULL; + node1->right = NULL; + + node2->data = &dataNode2; + node2->left = NULL; + node2->right = NULL; + + clearTree(root); + root = NULL; + + TEST_ASSERT_EQUAL_INT(0,treeSize(root)); +} + +void setUp(void) +{ + // Falls notwendig, kann hier Vorbereitungsarbeit gemacht werden +} + +void tearDown(void) +{ + // Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden +} + +int main() +{ + UNITY_BEGIN(); + + printf("============================\nNumbers tests\n============================\n"); + + RUN_TEST(sizeTest); + RUN_TEST(clearTest); + + return UNITY_END(); +} \ No newline at end of file diff --git a/test_numbers.c b/test_numbers.c index 04b5069..f98a45f 100644 --- a/test_numbers.c +++ b/test_numbers.c @@ -3,26 +3,47 @@ #include "numbers.h" #include "unity.h" -void createNumbersTest() +void test_createNumbers() { - unsigned int *array; unsigned int len = 6; - - array = createNumbers(len); - for (int i = 0; i < len; i++) - { - printf("%u ", array[i]); - } - printf("\n"); + unsigned int *array = createNumbers(len); TEST_ASSERT_NOT_NULL(array); + + unsigned int duplicate = getDuplicate(array, len); + TEST_ASSERT_NOT_EQUAL(0, duplicate); + + int counter = 0; + for (unsigned int i = 0; i < len; i++) + { + if (array[i] == duplicate) + counter++; + } + + TEST_ASSERT_EQUAL(2, counter); + + free(array); } -void duplicateTest() +void test_createNumbers_values() { - unsigned int array[6] = {1, 4, 5, 2, 3, 1}; unsigned int len = 6; + unsigned int *array = createNumbers(len); + TEST_ASSERT_NOT_NULL(array); - TEST_ASSERT_EQUAL_INT(1, getDuplicate(array, len)); + for (unsigned int i = 0; i < len; i++) + { + TEST_ASSERT_TRUE(array[i] >= 1); + TEST_ASSERT_TRUE(array[i] <= 2 * len); + } + + free(array); +} + +void test_getDuplicate() +{ + unsigned int array[6] = {1, 2, 4, 4, 6, 7}; + unsigned int duplicate = getDuplicate(array, 6); + TEST_ASSERT_EQUAL_UINT(4, duplicate); } void setUp(void) @@ -35,13 +56,15 @@ void tearDown(void) // Hier kann Bereinigungsarbeit nach jedem Test durchgeführt werden } -int main() +int main() { UNITY_BEGIN(); - printf("============================\nNumbers tests\n============================\n"); - RUN_TEST(createNumbersTest); - RUN_TEST(duplicateTest); + printf("\n============================\n Numbers tests\n============================\n"); + + RUN_TEST(test_createNumbers); + RUN_TEST(test_createNumbers_values); + RUN_TEST(test_getDuplicate); return UNITY_END(); } \ No newline at end of file diff --git a/test_stack.c b/test_stack.c index 2e59a8f..874e5f7 100644 --- a/test_stack.c +++ b/test_stack.c @@ -3,16 +3,33 @@ #include "stack.h" #include "unity.h" -void test_push(void) +void test_push(void) { + StackNode *stack = NULL; + int data1 = 10, data2 = 20; + + // Push elements to the stack + stack = push(stack, &data1); + stack = push(stack, &data2); + + // Check if the stack is not empty + TEST_ASSERT_NOT_NULL(stack); + + // Check if the top element is correct + int *topData = top(stack); + TEST_ASSERT_EQUAL_INT(20, *topData); // The last pushed element should be on top +} + +void test_push1(void) { - StackNode *testNode; + StackNode *testNode = NULL; int data = 1; // Test für leeren Stack - testNode = push(NULL, &data); + testNode = push(testNode, &data); TEST_ASSERT_NOT_NULL(&testNode); TEST_ASSERT_NULL(testNode->next); - TEST_ASSERT_EQUAL_INT(1, testNode->value); + int *temp = testNode->data; + TEST_ASSERT_EQUAL_INT(1, *temp); data = 2; @@ -21,26 +38,53 @@ void test_push(void) TEST_ASSERT_NOT_NULL(&testNode); TEST_ASSERT_NOT_NULL(testNode->next); TEST_ASSERT_NULL(testNode->next->next); - TEST_ASSERT_EQUAL_INT(1, testNode->value); - TEST_ASSERT_EQUAL_INT(2, testNode->next->value); + temp = testNode->data; + TEST_ASSERT_EQUAL_INT(2, *temp); + testNode = testNode->next; + temp = testNode->data; + TEST_ASSERT_EQUAL_INT(1, *temp); } -StackNode* setup(int value, StackNode* next) { +StackNode* setup(void *data, StackNode* next) { StackNode* node = malloc(sizeof(StackNode)); // allocate memory on heap if (node == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); // or handle the error differently } - node->value = value; + node->data = data; node->next = next; return node; } +void test_pop(void) { + StackNode *stack = NULL; + int data1 = 10, data2 = 20; -void test_pop(void) + // Push elements to the stack + stack = push(stack, &data1); + stack = push(stack, &data2); + + // Pop the top element + stack = pop(stack); + + // Check if the top element is now the first pushed element + int *topData = top(stack); + TEST_ASSERT_EQUAL_INT(10, *topData); // After popping, the first element should be on top + + // Pop the last element + stack = pop(stack); + + // Check if the stack is empty now + TEST_ASSERT_NULL(stack); // Stack should be NULL now +} +void test_pop2(void) { - StackNode* node2 = setup(3, NULL); - StackNode* node1 = setup(2, node2); - StackNode* header = setup(1, node1); + int x,y,z; + x = 1; + y = 2; + z = 3; + StackNode* node2 = setup(&z, NULL); + StackNode* node1 = setup(&y, node2); + StackNode* header = setup(&x, node1); StackNode* temp; temp = pop(header); @@ -56,35 +100,36 @@ void test_pop(void) TEST_ASSERT_NULL(node1->next); } -void test_top(void) -{ - StackNode* node2 = setup(3, NULL); - StackNode* node1 = setup(2, node2); - StackNode* header = setup(1, node1); +void test_top(void) { + StackNode *stack = NULL; + int data1 = 10, data2 = 20; - int data = *(int *)top(header); - TEST_ASSERT_EQUAL_INT(node2->value, data); + // Push elements to the stack + stack = push(stack, &data1); + stack = push(stack, &data2); + + // Check the top element + int *topData = top(stack); + TEST_ASSERT_EQUAL_INT(20, *topData); // The top element should be 20 (last pushed) + + // Pop the top element and check the new top + stack = pop(stack); + topData = top(stack); + TEST_ASSERT_EQUAL_INT(10, *topData); // Now the top element should be 10 } -void test_clear() +void test_top2(void) { - StackNode* node2 = setup(3, NULL); - StackNode* node1 = setup(2, node2); - StackNode* header = setup(1, node1); - StackNode* temp; - - clearStack(header); - temp = header; - - int after = 0; - while(temp) - { - after++; - temp = temp->next; - } + int x,y,z; + x = 1; + y = 2; + z = 3; + StackNode* node2 = setup(&z, NULL); + StackNode* node1 = setup(&y, node2); + StackNode* header = setup(&x, node1); - - TEST_ASSERT_NULL(after); + int data = *(int *)top(header); + TEST_ASSERT_EQUAL_INT(node2->data, data); } void setUp(void) @@ -106,7 +151,6 @@ int main() RUN_TEST(test_push); RUN_TEST(test_pop); RUN_TEST(test_top); - RUN_TEST(test_clear); return UNITY_END(); } \ No newline at end of file