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 <string.h>
#include "stack.h" #include "stack.h"
#include "bintree.h" #include "bintree.h"
//TODO: binären Suchbaum implementieren static TreeNode *createTreeNode(const void *data, size_t dataSize)
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), {
* `clearTree`: gibt den gesamten Baum frei (rekursiv), TreeNode *node = NULL;
* `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 (data == NULL || dataSize == 0)
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). {
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) 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. if (root == NULL)
// 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. 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) 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) 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. // 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);
} }

View File

@ -12,15 +12,18 @@ typedef struct node
struct node *right; struct node *right;
} TreeNode; } TreeNode;
// 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.
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // 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); 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, // Iterates over the tree in sorted order. If root is not NULL, a new iteration starts.
// push the top node and push all its left nodes. // If root is NULL, the next entry of the last tree is returned.
void *nextTreeData(TreeNode *root); void *nextTreeData(TreeNode *root);
// Releases all memory resources (including data copies).
// Releases all memory resources, including data copies.
void clearTree(TreeNode *root); void clearTree(TreeNode *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);

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 $(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@ $(CC) -c $(FLAGS) $^ -o $@
main.o: main.c
$(CC) -c $(FLAGS) main.c -o main.o
# -------------------------- # --------------------------
# Unit Tests # Unit Tests
# -------------------------- # --------------------------
unitTests: bintreeTests: bintree.o stack.o bintreeTests.c $(unityfolder)/unity.c
echo "needs to be implemented" $(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
# -------------------------- # --------------------------
clean: clean:
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
del /f *.o doble del /f *.o *.exe
else else
rm -f *.o doble rm -f *.o doble doble_initial runBintreeTests runNumbersTests
endif 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();
}