Compare commits

...

28 Commits

Author SHA1 Message Date
c3ce82150e Merge branch 'jonas' of https://git.efi.th-nuernberg.de/gitea/gloecknerni100842/I2_Projects into jonas 2025-12-05 14:45:26 +01:00
6dd9514f80 bintree.md added 2025-12-05 14:43:44 +01:00
2f3fee4cb2 small fix 2025-12-05 14:43:44 +01:00
0a30e04157 fixing error in dublicateRandomEntry 2025-12-05 14:43:44 +01:00
e4a7f9ac28 fix dublicate was at the end at all time 2025-12-05 14:43:44 +01:00
42243120eb small fixes 2025-12-05 14:43:44 +01:00
5857955dc0 added stackTest 2025-12-05 14:43:44 +01:00
3fdc249d86 binTreeTest added 2025-12-05 14:43:22 +01:00
a6850b83c3 makefile unitTest added 2025-12-05 14:43:22 +01:00
36e85dd4f4 bintree added 2025-12-05 14:42:50 +01:00
df9dedb1ad small fix numbersTest 2025-12-03 17:56:39 +01:00
cc318031be bintreeTest file added 2025-12-03 17:56:39 +01:00
179965193e stackTest file added 2025-12-03 17:56:39 +01:00
99477d3b58 small changes makefile 2025-12-03 17:54:15 +01:00
ef8340ba6b bintree.md added 2025-12-01 15:18:13 +01:00
9a8a346a1e small fix 2025-11-25 22:01:56 +01:00
40a6501fde fixing error in dublicateRandomEntry 2025-11-23 17:29:45 +01:00
52e83f52a2 fix dublicate was at the end at all time 2025-11-23 17:02:09 +01:00
7780bddc53 small fixes 2025-11-21 12:37:24 +01:00
0d561c0175 added stackTest 2025-11-21 12:35:12 +01:00
2950b10931 binTreeTest added 2025-11-21 10:17:58 +01:00
adc3ebc8be makefile unitTest added 2025-11-21 00:33:30 +01:00
85b5c181a0 bintree added 2025-11-21 00:33:08 +01:00
b0826ec057 stack completed 2025-11-21 00:32:57 +01:00
12742b46fe small fix numbersTest 2025-11-21 00:32:30 +01:00
cd13bbea4e bintreeTest file added 2025-11-21 00:32:10 +01:00
0c075ea18c stackTest file added 2025-11-21 00:31:48 +01:00
d6a439f85a small changes makefile 2025-11-19 23:37:32 +01:00
9 changed files with 455 additions and 21 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
!**/*.h
!**/*Makefile
!**/*.md
I2_Dobble/highscores.txt

View File

@ -8,11 +8,51 @@
* `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
static StackNode *iteratorStack = 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).
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
if (root == NULL)
{
// Neue Node anlegen
TreeNode *newNode = malloc(sizeof(TreeNode));
if (!newNode) return NULL;
newNode->data = malloc(dataSize);
if(!newNode->data)
{
free(newNode);
return NULL;
}
memcpy(newNode->data, data, dataSize);
newNode->left = NULL;
newNode->right = NULL;
if (isDuplicate)
*isDuplicate = 0;
return newNode;
}
int cmp = compareFct(data, root->data);
if (cmp == 0)
{
if (isDuplicate)
*isDuplicate = 1;
return root; // Einfügen verhindern
}
if (cmp < 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.
@ -20,17 +60,57 @@ 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(iteratorStack);
iteratorStack = NULL;
// Root + alle linken Nachfolger pushen
TreeNode *current = root;
while (current != NULL)
{
iteratorStack = push(iteratorStack, current);
current = current->left;
}
}
// Wenn Stack leer -> fertig
if (iteratorStack == NULL)
return NULL;
// Top-Node holen
TreeNode *node = (TreeNode *)top(iteratorStack);
iteratorStack = pop(iteratorStack);
// rechten Teilbaum + linke Kette pushen
TreeNode *right = node->right;
while (right != NULL)
{
iteratorStack = push(iteratorStack, right);
right = right->left;
}
return node->data;
}
// Releases all memory resources (including data copies).
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);
}

100
I2_Dobble/bintree.md Normal file
View File

@ -0,0 +1,100 @@
1) static StackNode *iteratorStack = NULL
-> Stack für nextTreeData
-> wird verwendet um nach und nach die Zahlen von klein nach groß auszugeben
-> muss da so stehen, weil ansonsten nextTreeData immer von vorne anfängt
2) addToTree -> soll ein Element an die richtige Stelle im Baum hinzufügen
-> wenn keine root angegeben ist (wenn entweder kein Baum vorhanden ist, oder die richtige Stelle gefunden wurde) soll ein neue Node erstellt werden.
-> Speicher reservieren
-> data nach newNode.data kopieren (memcpy) kopiert einfach nur den Inhalt ohne ihn zu interpretieren
-> pointer links und rechts werden NULL gesetzt, da keine anderen Datan vorhanden sind
-> isDublicate = 0, da kein Dublikat vorhanden sein kann
-> root.data wird mit data verglichen (größer, kleiner, gleich), um zu entscheiden, ob rechts oder links eingefügt werden soll
-> gleich -> Dublikat -> einfügen verhindern
-> größer -> rechts einfügen
-> kleiner -> links einfügen
-> eingefügt wird, in dem addToTree erneut aufgerufen wird, aber jetzt als root root.left/root.right übergeben wird
-> es wird erneut verglichen und wieder in den rechten, bzw. linken Teilbaum eingefügt, solange bis richtige Stelle im Baum erreicht ist -> einfügen des Wertes
3) nextTreeData
-> soll nacheinander die Werte des Binärbaums der größe nach ausgeben
-> Diese Funktion beruht auf einem richtigen Binär Baum (werte stehen an der richtigen Stelle)
-> dabei wird der iteratorStack verwendet, auf diesem sind immer Teilbereiche unseres Binärbaums vorhanden (in sortierter Reihenfolge), allerdings ist er nie vollständig, sondern wird im laufe des Programms immer durch fehlende Werte ergänzt
-> wenn root != NULL -> neuer Beginn bei einem ggf. anderen Baum
-> iteratorStack wird gelöscht um eventuelle "Rückstände" zu beseitigen
-> danach werden erstmal immer die jeweils linken Nodes in den Stack gepusht
-> im Stack liegt nun die kleinste Node ganz oben, danach werden die Werte immer größer, allerdings fehlen noch Werte dazwischen
-> anschließend wird sich die oberste Node aus dem Stack geholt und aus dem Stack entfernt -> Die ist der kleinste Wert im Baum und soll somit auch als erste zurückgegeben werden
-> jetzt wird auf dem Stack der rechte Teilbaum von unseren kleinsten Wert im Baum auf den Stack gepusht -> diese Werte sind alle größer als unsere Node, jedoch kleiner als die davor vorletzte Node im Stack -> DER STACK IST ALSO IMMER NOCH NACH DER GRÖßE SORTIERT
-> unser Stack hat jetzt den nächst größeren Wert im Baum als top Node -> ausgangssituation für nächsten Aufruf
-> gepeicherte node wird verwendet um node.data auszugeben
Beispiel Baum:
12
/ \
8 15
/ \ \
5 9 17
/ \
16 20
1) erst alle linken Nodes pushen -> 5
8
12
2) top Node (5) speichern und aus Stack entfernen -> 8
12
3) rechte Node und alle jeweils linken Nodes pushen -> 8
12
4) -> 5 wird ausgegeben (gepeicherte Node)
5) neuer Aufruf
6) top Node speichern (8) und aus Stack entfernen -> 12
7) rechte Node und alle jeweils linken Nodes pushen -> 9
12
8) -> 8 wird ausgegeben (gespeicherte Node)
9) neuer Aufruf
10) top Node speichern (9) und aus Stack entfernen -> 12
11) rechte Node und alle jeweils linken Nodes pushen -> 12
12) -> 9 wird ausgegeben (gespeicherte Node)
13) neuer Aufruf
14) top Node speichern (12) und aus Stack entfernen -> NULL
15) rechte Node und alle jeweils linken Nodes pushen -> 15
16) -> 12 wird ausgegeben (gespeicherte Node)
17) neuer Aufruf
18) top Node speichern (15) und aus Stack entfernen -> NULL
19) rechte Node und alle jeweils linken Nodes pushen -> 16
17
20) -> 15 wird ausgegeben (gespeicherte Node)
21) neuer Aufruf
22) top Node speichern (16) und aus Stack entfernen -> 17
23) rechte Node und alle jeweils linken Nodes pushen -> 17
24) -> 16 wird ausgegeben (gespeicherte Node)
25) neuer Aufruf
26) top Node speichern (17) und aus Stack entfernen -> NULL
27) rechte Node und alle jeweils linken Nodes pushen -> 20
28) -> 17 wird ausgegeben (gespeicherte Node)
29) neuer Aufruf
30) top Node speichern (20) und aus Stack entfernen -> NULL
31) rechte Node und alle jeweils linken Nodes pushen -> NULL
32) -> 20 wird ausgegeben (gespeicherte Node)
33) neuer Aufruf -> Stack = NULL -> fertig
4) treeSize
-> rekursiver Aufruf der Funktion
-> es wird jeweils die jeweils linke und rechte Node als neue root genommen
-> aufruf mit treeSize(root->left / root -> right)
-> es wird pro aufruf +1 gerechnet
-> am Ende wird die Node Anzahl zurückgegeben

119
I2_Dobble/bintreeTest.c Normal file
View File

@ -0,0 +1,119 @@
#include "unity.h"
#include "bintree.h"
#include <stdlib.h>
static int compare(const void *a, const void *b)
{
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
void setUp(void) { }
void tearDown(void) { }
void test_addToTree_single_element(void)
{
TreeNode *root = NULL;
int value = 10;
int dup = -1;
root = addToTree(root, &value, sizeof(int), compare, &dup);
TEST_ASSERT_NOT_NULL(root);
TEST_ASSERT_EQUAL_INT(10, *(int*)root->data);
TEST_ASSERT_EQUAL_INT(0, dup); // neuer Eintrag
clearTree(root);
}
void test_addToTree_multiple_elements_and_size(void)
{
TreeNode *root = NULL;
int values[] = {5, 3, 7, 1, 4};
int dup = -1;
for (int i = 0; i < 5; i++)
root = addToTree(root, &values[i], sizeof(int), compare, &dup);
TEST_ASSERT_EQUAL_UINT(5, treeSize(root));
clearTree(root);
}
void test_addToTree_duplicate_detection(void)
{
TreeNode *root = NULL;
int val = 42;
int dup;
root = addToTree(root, &val, sizeof(int), compare, &dup);
TEST_ASSERT_EQUAL(0, dup);
addToTree(root, &val, sizeof(int), compare, &dup);
TEST_ASSERT_EQUAL(1, dup);
clearTree(root);
}
void test_treeSize_empty_tree_detection(void)
{
TEST_ASSERT_EQUAL_UINT(0, treeSize(NULL));
}
void test_nextTreeData_returns_inorder(void)
{
TreeNode *root = NULL;
int values[] = {5, 3, 7, 2, 4, 6, 8};
// Einfügen
for (int i = 0; i < 7; i++)
root = addToTree(root, &values[i], sizeof(int), compare, NULL);
/* Erwartete Reihenfolge (inorder): 2,3,4,5,6,7,8 */
int expected[] = {2,3,4,5,6,7,8};
int idx = 0;
void *p = nextTreeData(root); // Iterator starten
while (p != NULL)
{
TEST_ASSERT_EQUAL_INT(expected[idx], *(int*)p);
idx++;
p = nextTreeData(NULL); // Fortsetzen mit NULL
}
TEST_ASSERT_EQUAL(7, idx); //alle Einträge geprüft
clearTree(root);
}
void test_treeSize_returns_correct_size()
{
TreeNode *root = NULL;
int values[] = {8, 3, 10, 1, 6, 14};
// ersten Baum aufbauen
for (int i = 0; i < 6; i++)
root = addToTree(root, &values[i], sizeof(int), compare, NULL);
TEST_ASSERT_EQUAL_UINT(6, treeSize(root));
// Baum löschen
clearTree(root);
root = NULL;
TEST_ASSERT_EQUAL_UINT(0, treeSize(root));
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_addToTree_single_element);
RUN_TEST(test_addToTree_multiple_elements_and_size);
RUN_TEST(test_addToTree_duplicate_detection);
RUN_TEST(test_treeSize_empty_tree_detection);
RUN_TEST(test_nextTreeData_returns_inorder);
RUN_TEST(test_treeSize_returns_correct_size);
return UNITY_END();
}

View File

@ -1,6 +1,5 @@
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -lm
ifeq ($(OS),Windows_NT)
include makefile_windows.variables
@ -28,33 +27,38 @@ doble_initial:
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $(LDFLAGS) $^ -o doble
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o doble
$(program_obj_filesobj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
$(program_obj_files): %.o: %.c
$(CC) -c $(CFLAGS) $^ -o $@
# --------------------------
# Unit Tests
# --------------------------
unitTests: numbersTest stackTest
unity_src = $(unityfolder)/unity.c
unitTests: numbersTest stackTest bintreeTest
./runNumbersTest
./runStackTest
./runBintreeTest
numbersTest: numbers.o bintree.o numbersTest.o $(unityfolder)/unity.c
$(CC) $(FLAGS) $(LDFLAGS) $^ -o runNumbersTest
numbersTest: numbers.o bintree.o stack.o numbersTest.c $(unity_src) stack.o
$(CC) $(CFLAGS) $(LDFLAGS) -I$(unityfolder) $^ -o runNumbersTest
stackTest: stack.o stackTest.o $(unityfolder)/unity.c
$(CC) $(FLAGS) $(LDFLAGS) $^ -o runStackTest
stackTest: stack.o stackTest.c $(unity_src)
$(CC) $(CFLAGS) $(LDFLAGS) -I$(unityfolder) $^ -o runStackTest
bintreeTest: bintree.o bintreeTest.c $(unity_src) stack.o
$(CC) $(CFLAGS) $(LDFLAGS) -I$(unityfolder) $^ -o runBintreeTest
%.o: %.c
$(CC) -c $(FLAGS) $< -o $@
$(CC) -c $(CFLAGS) $< -o $@
# --------------------------
# Clean
# --------------------------
clean:
ifeq ($(OS),Windows_NT)
del /f *.o doble runNumbersTest runStackTest
del /f *.o doble doble_initial runNumbersTest runStackTest runBintreeTest
else
rm -f *.o doble runNumbersTest runStackTest
rm -f *.o doble doble_initial runNumbersTest runStackTest runBintreeTest
endif

View File

@ -1,4 +1,4 @@
*createNumbers:
*createNumbers: -> numbers array gets filled with random entry with only one dublicate
-> check if len is greater than 2
-> create new array numbers, use malloc and check if correct
@ -7,7 +7,10 @@
-> add new value to tree using addToTree and rand()
-> addToTree sets isDup to 1, if value already exists
-> if value does not already exist -> add to numbers[]
->
-> stops at numbers[len -2]
static dublicateRandomEntry:
-> numbers[len-1] is filled with random already existing number
-> numbers[len -1] gets switched with other random entry -> dublicate is placed randwom in entry; without the switch, dublicate would always be at the end
getDublicate:
@ -15,7 +18,7 @@ getDublicate:
-> numbers (Zeiger != NULL) und len (min. 2) check
-> define new array numbersCopy
-> copy numbers to numbersCopy
-> simple loop to copy each element number -> numbersCopy
-> simple loop to copy each element from numbers to numbersCopy
-> sort numbersCopy with qsort
-> compare each element of numbersCopy with next element (if numbersCopy[i] == numbersCopy[i+1] -> dublicate was found, because same values are right next to each other)
-> return found dublicate

View File

@ -11,14 +11,33 @@
* 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.
static void dublicateRandomEntry (unsigned int *numbers, unsigned int len)
{
if (numbers && len > 2)
{
unsigned int dubIndx = rand() % (len - 1);
unsigned int copyIndx;
copyIndx = rand() % len;
numbers[len - 1] = numbers[dubIndx];
//switching last entry with random other entry
unsigned int temp;
temp = numbers[copyIndx];
numbers[copyIndx] = numbers[len - 1];
numbers[len - 1] = temp;
}
}
static int compare(const void *a, const void *b)
{
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
// 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)
@ -48,8 +67,7 @@ unsigned int *createNumbers(unsigned int len)
}
// Duplicate one random entry
unsigned int dupIndex = rand() % (len - 1);
numbers[len - 1] = numbers[dupIndex];
dublicateRandomEntry(numbers, len);
clearTree(root); //Notwendigkeit muss noch restlichem Code entnommen werden
return numbers;

View File

@ -1,3 +1,4 @@
#include <stdlib.h>
#include "numbers.h"
#include "unity.h"
#include "unity_internals.h"
@ -75,6 +76,9 @@ void test_complete_function_of_numbers(void)
free(arr);
}
void setUp(void) { }
void tearDown(void) { }
int main(void)
{
UNITY_BEGIN();

View File

@ -144,10 +144,98 @@ void test_clearStackFreesMemory(void)
}
*/
void test_push_should_add_new_node_at_top(void)
{
StackNode *stack = NULL;
int value = 42;
stack = push(stack, &value);
TEST_ASSERT_NOT_NULL(stack);
TEST_ASSERT_EQUAL_PTR(&value, stack->data);
TEST_ASSERT_NULL(stack->next);
clearStack(stack);
}
void test_push_multiple_should_chain_nodes_correctly(void)
{
int a = 1, b = 2;
StackNode *first = push(NULL, &a);
StackNode *second = push(first, &b);
TEST_ASSERT_EQUAL_PTR(&b, second->data);
TEST_ASSERT_EQUAL_PTR(first, second->next);
TEST_ASSERT_EQUAL_PTR(&a, first->data);
clearStack(second);
}
void test_top_should_return_null_on_empty_stack(void)
{
StackNode *stack = NULL;
TEST_ASSERT_NULL(top(stack));
}
void test_top_should_return_data_of_existing_node(void)
{
StackNode node;
int x = 99;
node.data = &x;
node.next = NULL;
TEST_ASSERT_EQUAL_PTR(&x, top(&node));
}
void test_pop_should_return_null_when_stack_empty(void)
{
StackNode *stack = NULL;
TEST_ASSERT_NULL(pop(stack));
}
void test_pop_should_remove_single_element(void)
{
StackNode *stack = malloc(sizeof(StackNode));
int x = 7;
stack->data = &x;
stack->next = NULL;
StackNode *result = pop(stack);
TEST_ASSERT_NULL(result); // Kein Element mehr übrig
}
void test_pop_should_remove_top_node_only(void)
{
// Manuell verkettete Liste aufbauen
StackNode *n1 = malloc(sizeof(StackNode));
StackNode *n2 = malloc(sizeof(StackNode));
int a = 1, b = 2;
n1->data = &a;
n1->next = NULL;
n2->data = &b;
n2->next = n1;
StackNode *result = pop(n2);
TEST_ASSERT_EQUAL_PTR(n1, result);
clearStack(result);
}
int main()
{
UNITY_BEGIN();
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
printf("\n============================\n Stack tests\n============================\n");
printf("-> Create Nodes (push)\n");
RUN_TEST(test_createNodeAbortsOnZeroData);
@ -163,5 +251,22 @@ int main()
RUN_TEST(test_outputTopFailsOnZero);
RUN_TEST(test_outputTopCorrect);
=======
>>>>>>> 0c075ea (stackTest file added)
=======
=======
>>>>>>> ef8340ba6b9e7a4d6bac8d0eb9b4b987a9316088
RUN_TEST(test_push_should_add_new_node_at_top);
RUN_TEST(test_push_multiple_should_chain_nodes_correctly);
RUN_TEST(test_top_should_return_null_on_empty_stack);
RUN_TEST(test_top_should_return_data_of_existing_node);
RUN_TEST(test_pop_should_return_null_when_stack_empty);
RUN_TEST(test_pop_should_remove_single_element);
RUN_TEST(test_pop_should_remove_top_node_only);
<<<<<<< HEAD
>>>>>>> 0d561c0 (added stackTest)
=======
>>>>>>> ef8340ba6b9e7a4d6bac8d0eb9b4b987a9316088
return UNITY_END();
}