generated from freudenreichan/info2Praktikum-DobleSpiel
bintree and tests
This commit is contained in:
parent
4b9366c887
commit
ccd912be91
132
bintree.c
132
bintree.c
@ -1,36 +1,144 @@
|
||||
#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. */
|
||||
static TreeNode *createTreeNode(const void *data, size_t dataSize)
|
||||
{
|
||||
TreeNode *node = NULL;
|
||||
|
||||
// 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 (data == NULL || dataSize == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = (TreeNode *)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;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Adds a copy of data's pointer destination to the tree using compareFct for ordering.
|
||||
// If isDuplicate is NULL, duplicates are accepted. Otherwise duplicates are ignored and
|
||||
// isDuplicate is set to 1. If a new value is inserted, isDuplicate is set to 0.
|
||||
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
|
||||
{
|
||||
int compareResult = 0;
|
||||
|
||||
if (data == NULL || dataSize == 0 || compareFct == NULL)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
if (root == NULL)
|
||||
{
|
||||
TreeNode *newNode = createTreeNode(data, dataSize);
|
||||
|
||||
if (newNode != NULL && isDuplicate != NULL)
|
||||
{
|
||||
*isDuplicate = 0;
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
compareResult = compareFct(data, root->data);
|
||||
|
||||
if (compareResult == 0 && isDuplicate != NULL)
|
||||
{
|
||||
*isDuplicate = 1;
|
||||
return root;
|
||||
}
|
||||
|
||||
if (compareResult < 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.
|
||||
static StackNode *pushLeftPath(StackNode *stack, TreeNode *node)
|
||||
{
|
||||
while (node != NULL)
|
||||
{
|
||||
stack = push(stack, node);
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
// Iterates over the tree in sorted order. If root is not NULL, a new iteration starts.
|
||||
// If root is NULL, the next element of the last tree is returned.
|
||||
void *nextTreeData(TreeNode *root)
|
||||
{
|
||||
static StackNode *iteratorStack = NULL;
|
||||
TreeNode *currentNode = NULL;
|
||||
void *data = NULL;
|
||||
|
||||
if (root != NULL)
|
||||
{
|
||||
clearStack(iteratorStack);
|
||||
iteratorStack = NULL;
|
||||
iteratorStack = pushLeftPath(iteratorStack, root);
|
||||
}
|
||||
|
||||
currentNode = (TreeNode *)top(iteratorStack);
|
||||
|
||||
if (currentNode == NULL)
|
||||
{
|
||||
clearStack(iteratorStack);
|
||||
iteratorStack = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iteratorStack = pop(iteratorStack);
|
||||
data = currentNode->data;
|
||||
iteratorStack = pushLeftPath(iteratorStack, currentNode->right);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Releases all memory resources (including data copies).
|
||||
// Releases all memory resources, including the copied data in each tree node.
|
||||
void clearTree(TreeNode *root)
|
||||
{
|
||||
|
||||
if (root != NULL)
|
||||
{
|
||||
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 == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1 + treeSize(root->left) + treeSize(root->right);
|
||||
}
|
||||
15
bintree.h
15
bintree.h
@ -12,15 +12,18 @@ typedef struct node
|
||||
struct node *right;
|
||||
} TreeNode;
|
||||
|
||||
// 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).
|
||||
// Adds a copy of data's pointer destination to the tree using compareFct for ordering.
|
||||
// Accepts duplicates if isDuplicate is NULL. Otherwise duplicates are ignored and
|
||||
// isDuplicate is set to 1. If a new entry is added, isDuplicate is set to 0.
|
||||
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate);
|
||||
// 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.
|
||||
|
||||
// Iterates over the tree in sorted order. If root is not NULL, a new iteration starts.
|
||||
// If root is NULL, the next entry of the last tree is returned.
|
||||
void *nextTreeData(TreeNode *root);
|
||||
// Releases all memory resources (including data copies).
|
||||
|
||||
// Releases all memory resources, including data copies.
|
||||
void clearTree(TreeNode *root);
|
||||
|
||||
// Returns the number of entries in the tree given by root.
|
||||
unsigned int treeSize(const TreeNode *root);
|
||||
|
||||
|
||||
180
bintreeTests.c
Normal file
180
bintreeTests.c
Normal file
@ -0,0 +1,180 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "bintree.h"
|
||||
|
||||
static int compareUnsignedInt(const void *arg1, const void *arg2)
|
||||
{
|
||||
unsigned int number1 = *(const unsigned int *)arg1;
|
||||
unsigned int number2 = *(const unsigned int *)arg2;
|
||||
|
||||
if (number1 < number2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (number1 > number2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_addToTreeCreatesRootNodeAndCopiesData(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int value = 10;
|
||||
|
||||
root = addToTree(root, &value, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
value = 99;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(root);
|
||||
TEST_ASSERT_NOT_NULL(root->data);
|
||||
TEST_ASSERT_EQUAL_UINT32(10, *(unsigned int *)root->data);
|
||||
TEST_ASSERT_NULL(root->left);
|
||||
TEST_ASSERT_NULL(root->right);
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_addToTreeInsertsSmallerValueOnLeftSide(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int value1 = 10;
|
||||
unsigned int value2 = 5;
|
||||
|
||||
root = addToTree(root, &value1, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
root = addToTree(root, &value2, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(root);
|
||||
TEST_ASSERT_NOT_NULL(root->left);
|
||||
TEST_ASSERT_EQUAL_UINT32(5, *(unsigned int *)root->left->data);
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_addToTreeInsertsGreaterValueOnRightSide(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int value1 = 10;
|
||||
unsigned int value2 = 20;
|
||||
|
||||
root = addToTree(root, &value1, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
root = addToTree(root, &value2, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(root);
|
||||
TEST_ASSERT_NOT_NULL(root->right);
|
||||
TEST_ASSERT_EQUAL_UINT32(20, *(unsigned int *)root->right->data);
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_addToTreeDetectsDuplicateWhenFlagIsUsed(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int value1 = 10;
|
||||
unsigned int value2 = 10;
|
||||
int isDuplicate = 0;
|
||||
|
||||
root = addToTree(root, &value1, sizeof(unsigned int), compareUnsignedInt, &isDuplicate);
|
||||
TEST_ASSERT_EQUAL_INT(0, isDuplicate);
|
||||
|
||||
root = addToTree(root, &value2, sizeof(unsigned int), compareUnsignedInt, &isDuplicate);
|
||||
TEST_ASSERT_EQUAL_INT(1, isDuplicate);
|
||||
TEST_ASSERT_EQUAL_UINT32(1, treeSize(root));
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_addToTreeAcceptsDuplicateWhenFlagIsNull(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int value = 10;
|
||||
|
||||
root = addToTree(root, &value, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
root = addToTree(root, &value, sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(2, treeSize(root));
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_treeSizeReturnsCorrectNumberOfNodes(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int values[] = {10, 5, 15, 3, 7};
|
||||
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
{
|
||||
root = addToTree(root, &values[i], sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(5, treeSize(root));
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_nextTreeDataReturnsValuesInSortedOrder(void)
|
||||
{
|
||||
TreeNode *root = NULL;
|
||||
unsigned int values[] = {10, 5, 15, 3, 7};
|
||||
unsigned int expectedValues[] = {3, 5, 7, 10, 15};
|
||||
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
{
|
||||
root = addToTree(root, &values[i], sizeof(unsigned int), compareUnsignedInt, NULL);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 5; i++)
|
||||
{
|
||||
unsigned int *currentValue = NULL;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
currentValue = (unsigned int *)nextTreeData(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue = (unsigned int *)nextTreeData(NULL);
|
||||
}
|
||||
|
||||
TEST_ASSERT_NOT_NULL(currentValue);
|
||||
TEST_ASSERT_EQUAL_UINT32(expectedValues[i], *currentValue);
|
||||
}
|
||||
|
||||
TEST_ASSERT_NULL(nextTreeData(NULL));
|
||||
|
||||
clearTree(root);
|
||||
}
|
||||
|
||||
void test_clearTreeDoesNotCrashOnNull(void)
|
||||
{
|
||||
clearTree(NULL);
|
||||
TEST_PASS();
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
printf("\n============================\nBinary tree tests\n============================\n");
|
||||
RUN_TEST(test_addToTreeCreatesRootNodeAndCopiesData);
|
||||
RUN_TEST(test_addToTreeInsertsSmallerValueOnLeftSide);
|
||||
RUN_TEST(test_addToTreeInsertsGreaterValueOnRightSide);
|
||||
RUN_TEST(test_addToTreeDetectsDuplicateWhenFlagIsUsed);
|
||||
RUN_TEST(test_addToTreeAcceptsDuplicateWhenFlagIsNull);
|
||||
RUN_TEST(test_treeSizeReturnsCorrectNumberOfNodes);
|
||||
RUN_TEST(test_nextTreeDataReturnsValuesInSortedOrder);
|
||||
RUN_TEST(test_clearTreeDoesNotCrashOnNull);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
25
makefile
25
makefile
@ -26,24 +26,39 @@ doble_initial:
|
||||
# --------------------------
|
||||
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
|
||||
|
||||
$(program_obj_files): %.o: %.c
|
||||
$(CC) -c $(FLAGS) $^ -o $@
|
||||
|
||||
main.o: main.c
|
||||
$(CC) -c $(FLAGS) main.c -o main.o
|
||||
|
||||
# --------------------------
|
||||
# Unit Tests
|
||||
# --------------------------
|
||||
unitTests:
|
||||
echo "needs to be implemented"
|
||||
bintreeTests: bintree.o stack.o bintreeTests.c $(unityfolder)/unity.c
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -o runBintreeTests bintreeTests.c bintree.o stack.o $(unityfolder)/unity.c
|
||||
|
||||
numbersTests: numbers.o bintree.o stack.o numbersTests.c $(unityfolder)/unity.c
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -o runNumbersTests numbersTests.c numbers.o bintree.o stack.o $(unityfolder)/unity.c
|
||||
|
||||
unitTests: bintreeTests numbersTests
|
||||
ifeq ($(OS),Windows_NT)
|
||||
.\runBintreeTests.exe
|
||||
.\runNumbersTests.exe
|
||||
else
|
||||
./runBintreeTests
|
||||
./runNumbersTests
|
||||
endif
|
||||
|
||||
# --------------------------
|
||||
# Clean
|
||||
# --------------------------
|
||||
clean:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
del /f *.o doble
|
||||
del /f *.o *.exe
|
||||
else
|
||||
rm -f *.o doble
|
||||
rm -f *.o doble doble_initial runBintreeTests runNumbersTests
|
||||
endif
|
||||
85
numbersTests.c
Normal file
85
numbersTests.c
Normal file
@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "unity.h"
|
||||
#include "numbers.h"
|
||||
|
||||
void test_getDuplicateReturnsDuplicateFromUnsortedArray(void)
|
||||
{
|
||||
unsigned int numbers[] = {8, 3, 12, 5, 3, 20};
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(3, getDuplicate(numbers, 6));
|
||||
}
|
||||
|
||||
void test_getDuplicateReturnsZeroForNullArray(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_UINT32(0, getDuplicate(NULL, 5));
|
||||
}
|
||||
|
||||
void test_getDuplicateReturnsZeroIfThereIsNoDuplicate(void)
|
||||
{
|
||||
unsigned int numbers[] = {1, 2, 3, 4, 5};
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(0, getDuplicate(numbers, 5));
|
||||
}
|
||||
|
||||
void test_getDuplicateDoesNotChangeOriginalArrayOrder(void)
|
||||
{
|
||||
unsigned int numbers[] = {9, 4, 7, 4, 2};
|
||||
unsigned int expectedNumbers[] = {9, 4, 7, 4, 2};
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(4, getDuplicate(numbers, 5));
|
||||
TEST_ASSERT_EQUAL_UINT32_ARRAY(expectedNumbers, numbers, 5);
|
||||
}
|
||||
|
||||
void test_createNumbersReturnsArrayWithCorrectDuplicate(void)
|
||||
{
|
||||
const unsigned int len = 20;
|
||||
unsigned int *numbers = createNumbers(len);
|
||||
unsigned int duplicate = 0;
|
||||
unsigned int duplicateCount = 0;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(numbers);
|
||||
|
||||
duplicate = getDuplicate(numbers, len);
|
||||
TEST_ASSERT_NOT_EQUAL(0, duplicate);
|
||||
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
{
|
||||
if (numbers[i] == duplicate)
|
||||
{
|
||||
duplicateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(2, duplicateCount);
|
||||
|
||||
free(numbers);
|
||||
}
|
||||
|
||||
void test_createNumbersReturnsNullForTooSmallLength(void)
|
||||
{
|
||||
TEST_ASSERT_NULL(createNumbers(1));
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
printf("\n============================\nNumbers tests\n============================\n");
|
||||
RUN_TEST(test_getDuplicateReturnsDuplicateFromUnsortedArray);
|
||||
RUN_TEST(test_getDuplicateReturnsZeroForNullArray);
|
||||
RUN_TEST(test_getDuplicateReturnsZeroIfThereIsNoDuplicate);
|
||||
RUN_TEST(test_getDuplicateDoesNotChangeOriginalArrayOrder);
|
||||
RUN_TEST(test_createNumbersReturnsArrayWithCorrectDuplicate);
|
||||
RUN_TEST(test_createNumbersReturnsNullForTooSmallLength);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user