bintree and tests

This commit is contained in:
DESKTOP-0TGNH6T\alial 2026-06-08 16:45:03 +02:00
parent 4b9366c887
commit ccd912be91
5 changed files with 414 additions and 23 deletions

134
bintree.c
View File

@ -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;
}
// 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.
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;
}
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);
}
// Releases all memory resources (including data copies).
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 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);
}

View File

@ -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
View 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();
}

View File

@ -32,18 +32,33 @@ doble : main.o $(program_obj_files)
$(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
View 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();
}