Compare commits

..
1 Commits
Author SHA1 Message Date
gessnitzerlu98886 f5af439e99 erste tests 2025-12-12 14:33:45 +01:00
36 changed files with 1480 additions and 159 deletions

No files matched your search

-62
View File
@@ -1,62 +0,0 @@
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
Startcode/doble_initial
Startcode/doble
Startcode/unitTests
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# IDE folders
.vscode/
.idea/
# macOS
.DS_Store
Binary file not shown.
-36
View File
@@ -1,36 +0,0 @@
#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. */
// 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)
{
}
// 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.
void *nextTreeData(TreeNode *root)
{
}
// 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)
{
}
-26
View File
@@ -1,26 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
* 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.
unsigned int *createNumbers(unsigned int len)
{
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
}
-33
View File
@@ -1,33 +0,0 @@
#include <stdlib.h>
#include "stack.h"
//TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element,
* `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
}
// 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)
{
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
}
+423
View File
@@ -0,0 +1,423 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "bintree.h"
#define GREEN "\033[0;32m"
#define RED "\033[0;31m"
#define RESET "\033[0m"
#define BLUE "\033[0;34m"
int testsPassed = 0;
int testsFailed = 0;
void printTestResult(const char *testName, int passed)
{
if (passed)
{
printf(GREEN "[PASS]" RESET " %s\n", testName);
testsPassed++;
}
else
{
printf(RED "[FAIL]" RESET " %s\n", testName);
testsFailed++;
}
}
// Vergleichsfunktion für Integers
int compareInt(const void *arg1, const void *arg2)
{
int val1 = *(const int *)arg1;
int val2 = *(const int *)arg2;
if (val1 < val2) return -1;
if (val1 > val2) return 1;
return 0;
}
// Vergleichsfunktion für Strings
int compareString(const void *arg1, const void *arg2)
{
return strcmp(*(const char **)arg1, *(const char **)arg2);
}
// Test 1: addToTree mit einem Element
void test_add_single_element()
{
printf(BLUE "\n--- Test 1: addToTree mit einem Element ---" RESET "\n");
TreeNode *root = NULL;
int value = 42;
root = addToTree(root, &value, sizeof(int), compareInt, NULL);
printTestResult("Baum wurde erstellt", root != NULL);
printTestResult("Root-Daten sind korrekt", root != NULL && *(int *)root->data == 42);
printTestResult("Root hat keine Kinder", root != NULL && root->left == NULL && root->right == NULL);
clearTree(root);
}
// Test 2: addToTree mit mehreren Elementen
void test_add_multiple_elements()
{
printf(BLUE "\n--- Test 2: addToTree mit mehreren Elementen ---" RESET "\n");
TreeNode *root = NULL;
int values[] = {50, 30, 70, 20, 40, 60, 80};
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
printTestResult("Baum mit 7 Elementen erstellt", root != NULL);
printTestResult("Root ist 50", *(int *)root->data == 50);
printTestResult("Linkes Kind ist 30", root->left != NULL && *(int *)root->left->data == 30);
printTestResult("Rechtes Kind ist 70", root->right != NULL && *(int *)root->right->data == 70);
clearTree(root);
}
// Test 3: addToTree mit Duplikat-Erkennung
void test_duplicate_detection()
{
printf(BLUE "\n--- Test 3: Duplikat-Erkennung ---" RESET "\n");
TreeNode *root = NULL;
int value1 = 42;
int value2 = 17;
int value3 = 42; // Duplikat!
int isDuplicate = 0;
root = addToTree(root, &value1, sizeof(int), compareInt, &isDuplicate);
printTestResult("Erstes Element: kein Duplikat", isDuplicate == 0);
isDuplicate = 0;
root = addToTree(root, &value2, sizeof(int), compareInt, &isDuplicate);
printTestResult("Zweites Element: kein Duplikat", isDuplicate == 0);
isDuplicate = 0;
root = addToTree(root, &value3, sizeof(int), compareInt, &isDuplicate);
printTestResult("Drittes Element: Duplikat erkannt", isDuplicate == 1);
clearTree(root);
}
// Test 4: addToTree mit Duplikaten erlaubt
void test_allow_duplicates()
{
printf(BLUE "\n--- Test 4: Duplikate erlauben (isDuplicate = NULL) ---" RESET "\n");
TreeNode *root = NULL;
int values[] = {50, 30, 50, 30}; // Mit Duplikaten
for (int i = 0; i < 4; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
unsigned int size = treeSize(root);
printTestResult("Alle 4 Elemente wurden eingefuegt (inkl. Duplikate)", size == 4);
clearTree(root);
}
// Test 5: treeSize
void test_tree_size()
{
printf(BLUE "\n--- Test 5: treeSize ---" RESET "\n");
TreeNode *root = NULL;
printTestResult("Leerer Baum hat Groesse 0", treeSize(root) == 0);
int values[] = {50, 30, 70, 20, 40};
for (int i = 0; i < 5; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
printTestResult("Baum mit 5 Elementen hat Groesse 5", treeSize(root) == 5);
// Füge mehr hinzu
int value6 = 60;
int value7 = 80;
root = addToTree(root, &value6, sizeof(int), compareInt, NULL);
root = addToTree(root, &value7, sizeof(int), compareInt, NULL);
printTestResult("Nach Hinzufuegen von 2 Elementen: Groesse 7", treeSize(root) == 7);
clearTree(root);
}
// Test 6: nextTreeData In-Order Traversierung
void test_next_tree_data()
{
printf(BLUE "\n--- Test 6: nextTreeData (In-Order Traversierung) ---" RESET "\n");
TreeNode *root = NULL;
int values[] = {50, 30, 70, 20, 40, 60, 80};
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
// Erwartete Reihenfolge: 20, 30, 40, 50, 60, 70, 80 (sortiert!)
int expected[] = {20, 30, 40, 50, 60, 70, 80};
int index = 0;
int allCorrect = 1;
int *data = (int *)nextTreeData(root);
while (data != NULL)
{
if (index >= 7 || *data != expected[index])
{
allCorrect = 0;
printf(" Fehler bei Index %d: Erwartet %d, bekommen %d\n", index, expected[index], *data);
}
index++;
data = (int *)nextTreeData(NULL);
}
printTestResult("In-Order Traversierung gibt sortierte Reihenfolge", allCorrect && index == 7);
clearTree(root);
}
// Test 7: nextTreeData mit einzelnem Element
void test_next_tree_data_single()
{
printf(BLUE "\n--- Test 7: nextTreeData mit einem Element ---" RESET "\n");
TreeNode *root = NULL;
int value = 42;
root = addToTree(root, &value, sizeof(int), compareInt, NULL);
int *data = (int *)nextTreeData(root);
int correct = (data != NULL && *data == 42);
data = (int *)nextTreeData(NULL);
correct = correct && (data == NULL);
printTestResult("nextTreeData mit einem Element funktioniert", correct);
clearTree(root);
}
// Test 8: nextTreeData mit leerem Baum
void test_next_tree_data_empty()
{
printf(BLUE "\n--- Test 8: nextTreeData mit leerem Baum ---" RESET "\n");
TreeNode *root = NULL;
int *data = (int *)nextTreeData(root);
printTestResult("nextTreeData mit leerem Baum gibt NULL zurueck", data == NULL);
}
// Test 9: Mehrfache Traversierungen
void test_multiple_traversals()
{
printf(BLUE "\n--- Test 9: Mehrfache Traversierungen ---" RESET "\n");
TreeNode *root = NULL;
int values[] = {50, 30, 70};
for (int i = 0; i < 3; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
// Erste Traversierung
int count1 = 0;
int *data = (int *)nextTreeData(root);
while (data != NULL)
{
count1++;
data = (int *)nextTreeData(NULL);
}
// Zweite Traversierung (neu starten)
int count2 = 0;
data = (int *)nextTreeData(root);
while (data != NULL)
{
count2++;
data = (int *)nextTreeData(NULL);
}
printTestResult("Mehrfache Traversierungen moeglich", count1 == 3 && count2 == 3);
clearTree(root);
}
// Test 10: clearTree
void test_clear_tree()
{
printf(BLUE "\n--- Test 10: clearTree ---" RESET "\n");
TreeNode *root = NULL;
int values[] = {50, 30, 70, 20, 40, 60, 80};
for (int i = 0; i < 7; i++)
{
root = addToTree(root, &values[i], sizeof(int), compareInt, NULL);
}
clearTree(root);
root = NULL;
printTestResult("clearTree ausgefuehrt (valgrind prueft Speicher)", 1);
// Neuer Baum nach Clear
int newValue = 100;
root = addToTree(root, &newValue, sizeof(int), compareInt, NULL);
printTestResult("Nach clearTree kann neuer Baum aufgebaut werden", root != NULL && *(int *)root->data == 100);
clearTree(root);
}
// Test 11: Strings im Baum
void test_string_tree()
{
printf(BLUE "\n--- Test 11: Baum mit Strings ---" RESET "\n");
TreeNode *root = NULL;
char *words[] = {"dog", "cat", "elephant", "ant", "bear"};
for (int i = 0; i < 5; i++)
{
root = addToTree(root, &words[i], sizeof(char *), compareString, NULL);
}
printTestResult("String-Baum erstellt", root != NULL);
// Traversierung sollte alphabetisch sortiert sein
char *expected[] = {"ant", "bear", "cat", "dog", "elephant"};
int index = 0;
int allCorrect = 1;
char **data = (char **)nextTreeData(root);
while (data != NULL)
{
if (index >= 5 || strcmp(*data, expected[index]) != 0)
{
allCorrect = 0;
printf(" Fehler bei Index %d: Erwartet '%s', bekommen '%s'\n", index, expected[index], *data);
}
index++;
data = (char **)nextTreeData(NULL);
}
printTestResult("String-Baum gibt alphabetisch sortierte Reihenfolge", allCorrect && index == 5);
clearTree(root);
}
// Test 12: Stress-Test mit vielen Elementen
void test_large_tree()
{
printf(BLUE "\n--- Test 12: Stress-Test (1000 Elemente) ---" RESET "\n");
TreeNode *root = NULL;
// 1000 zufällige Zahlen einfügen
for (int i = 0; i < 1000; i++)
{
int value = i;
root = addToTree(root, &value, sizeof(int), compareInt, NULL);
}
printTestResult("1000 Elemente eingefuegt", treeSize(root) == 1000);
// Traversierung zählen
int count = 0;
int *data = (int *)nextTreeData(root);
while (data != NULL)
{
count++;
data = (int *)nextTreeData(NULL);
}
printTestResult("Traversierung ueber alle 1000 Elemente", count == 1000);
clearTree(root);
}
// Test 13: Einseitiger Baum (nur rechts)
void test_unbalanced_tree()
{
printf(BLUE "\n--- Test 13: Einseitiger Baum ---" RESET "\n");
TreeNode *root = NULL;
// Aufsteigende Reihenfolge -> nur rechte Kinder
for (int i = 1; i <= 5; i++)
{
root = addToTree(root, &i, sizeof(int), compareInt, NULL);
}
printTestResult("Einseitiger Baum erstellt", treeSize(root) == 5);
// Traversierung sollte trotzdem funktionieren
int count = 0;
int *data = (int *)nextTreeData(root);
while (data != NULL)
{
count++;
data = (int *)nextTreeData(NULL);
}
printTestResult("Traversierung ueber einseitigen Baum funktioniert", count == 5);
clearTree(root);
}
int main()
{
printf("\n");
printf("+----------------------------------------------+\n");
printf("| BINARY TREE UNIT TESTS |\n");
printf("+----------------------------------------------+\n");
test_add_single_element();
test_add_multiple_elements();
test_duplicate_detection();
test_allow_duplicates();
test_tree_size();
test_next_tree_data();
test_next_tree_data_single();
test_next_tree_data_empty();
test_multiple_traversals();
test_clear_tree();
test_string_tree();
test_large_tree();
test_unbalanced_tree();
printf("\n");
printf("+----------------------------------------------+\n");
printf("| TEST ZUSAMMENFASSUNG |\n");
printf("+----------------------------------------------+\n");
printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed);
printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed);
printf("Gesamt: %d\n", testsPassed + testsFailed);
if (testsFailed == 0)
{
printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET);
return EXIT_SUCCESS;
}
else
{
printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET);
return EXIT_FAILURE;
}
}
+336
View File
@@ -0,0 +1,336 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include "numbers.h"
#define GREEN "\033[0;32m"
#define RED "\033[0;31m"
#define RESET "\033[0m"
#define BLUE "\033[0;34m"
int testsPassed = 0;
int testsFailed = 0;
void printTestResult(const char *testName, int passed)
{
if (passed)
{
printf(GREEN "[PASS]" RESET " %s\n", testName);
testsPassed++;
}
else
{
printf(RED "[FAIL]" RESET " %s\n", testName);
testsFailed++;
}
}
// Hilfsfunktion: Prüft ob eine Zahl im Array vorkommt
int countOccurrences(const unsigned int *array, unsigned int len, unsigned int value)
{
int count = 0;
for (unsigned int i = 0; i < len; i++)
{
if (array[i] == value)
count++;
}
return count;
}
// Hilfsfunktion: Prüft ob alle Zahlen im gültigen Bereich sind
int allNumbersInRange(const unsigned int *array, unsigned int len, unsigned int min, unsigned int max)
{
for (unsigned int i = 0; i < len; i++)
{
if (array[i] < min || array[i] > max)
return 0;
}
return 1;
}
// Test 1: createNumbers mit kleiner Anzahl
void test_create_numbers_small()
{
printf(BLUE "\n--- Test 1: createNumbers mit 5 Zahlen ---" RESET "\n");
unsigned int len = 5;
unsigned int *numbers = createNumbers(len);
printTestResult("createNumbers gibt nicht-NULL zurueck", numbers != NULL);
if (numbers != NULL)
{
// Alle Zahlen zwischen 1 und 2*len?
int inRange = allNumbersInRange(numbers, len, 1, 2 * len);
printTestResult("Alle Zahlen im Bereich [1, 10]", inRange);
// Genau ein Duplikat zählen
int duplicateCount = 0;
for (unsigned int i = 0; i < len; i++)
{
int occurrences = countOccurrences(numbers, len, numbers[i]);
if (occurrences == 2)
duplicateCount++;
}
// duplicateCount sollte 2 sein (2 mal die gleiche Zahl)
printTestResult("Genau ein Duplikat vorhanden", duplicateCount == 2);
free(numbers);
}
}
// Test 2: createNumbers mit mittlerer Anzahl
void test_create_numbers_medium()
{
printf(BLUE "\n--- Test 2: createNumbers mit 20 Zahlen ---" RESET "\n");
unsigned int len = 20;
unsigned int *numbers = createNumbers(len);
printTestResult("createNumbers(20) gibt nicht-NULL zurueck", numbers != NULL);
if (numbers != NULL)
{
int inRange = allNumbersInRange(numbers, len, 1, 2 * len);
printTestResult("Alle Zahlen im Bereich [1, 40]", inRange);
free(numbers);
}
}
// Test 3: createNumbers mit Minimum (3 Zahlen)
void test_create_numbers_minimum()
{
printf(BLUE "\n--- Test 3: createNumbers mit Minimum (3 Zahlen) ---" RESET "\n");
unsigned int len = 3;
unsigned int *numbers = createNumbers(len);
printTestResult("createNumbers(3) funktioniert", numbers != NULL);
if (numbers != NULL)
{
int inRange = allNumbersInRange(numbers, len, 1, 2 * len);
printTestResult("Alle Zahlen im Bereich [1, 6]", inRange);
free(numbers);
}
}
// Test 4: createNumbers mit größerer Anzahl
void test_create_numbers_large()
{
printf(BLUE "\n--- Test 4: createNumbers mit 100 Zahlen ---" RESET "\n");
unsigned int len = 100;
unsigned int *numbers = createNumbers(len);
printTestResult("createNumbers(100) gibt nicht-NULL zurueck", numbers != NULL);
if (numbers != NULL)
{
int inRange = allNumbersInRange(numbers, len, 1, 2 * len);
printTestResult("Alle Zahlen im Bereich [1, 200]", inRange);
free(numbers);
}
}
// Test 5: getDuplicate findet das Duplikat
void test_get_duplicate_finds_duplicate()
{
printf(BLUE "\n--- Test 5: getDuplicate findet Duplikat ---" RESET "\n");
// Manuelles Test-Array mit bekanntem Duplikat
unsigned int testArray[] = {5, 12, 7, 3, 12, 9};
unsigned int len = 6;
unsigned int duplicate = getDuplicate(testArray, len);
printTestResult("getDuplicate findet korrektes Duplikat (12)", duplicate == 12);
}
// Test 6: getDuplicate mit sortiertem Array
void test_get_duplicate_sorted()
{
printf(BLUE "\n--- Test 6: getDuplicate mit sortiertem Array ---" RESET "\n");
unsigned int testArray[] = {1, 2, 3, 3, 4, 5};
unsigned int len = 6;
unsigned int duplicate = getDuplicate(testArray, len);
printTestResult("getDuplicate funktioniert mit sortiertem Array", duplicate == 3);
}
// Test 7: getDuplicate mit unsortiertem Array
void test_get_duplicate_unsorted()
{
printf(BLUE "\n--- Test 7: getDuplicate mit unsortiertem Array ---" RESET "\n");
unsigned int testArray[] = {42, 17, 8, 99, 3, 42, 55};
unsigned int len = 7;
unsigned int duplicate = getDuplicate(testArray, len);
printTestResult("getDuplicate funktioniert mit unsortiertem Array", duplicate == 42);
}
// Test 8: Integration - createNumbers und getDuplicate
void test_integration_create_and_get()
{
printf(BLUE "\n--- Test 8: Integration createNumbers + getDuplicate ---" RESET "\n");
int allCorrect = 1;
// Teste mehrmals mit verschiedenen Größen
unsigned int sizes[] = {5, 10, 20, 50};
for (int i = 0; i < 4; i++)
{
unsigned int len = sizes[i];
unsigned int *numbers = createNumbers(len);
if (numbers == NULL)
{
allCorrect = 0;
break;
}
unsigned int duplicate = getDuplicate(numbers, len);
// Prüfe ob das gefundene Duplikat tatsächlich 2x vorkommt
int occurrences = countOccurrences(numbers, len, duplicate);
if (duplicate == 0 || occurrences != 2)
{
printf(" Fehler bei len=%u: duplicate=%u, occurrences=%d\n", len, duplicate, occurrences);
allCorrect = 0;
}
free(numbers);
}
printTestResult("Integration funktioniert fuer verschiedene Groessen", allCorrect);
}
// Test 9: Fehlerbehandlung - NULL-Pointer
void test_get_duplicate_null()
{
printf(BLUE "\n--- Test 9: Fehlerbehandlung NULL-Pointer ---" RESET "\n");
unsigned int result = getDuplicate(NULL, 10);
printTestResult("getDuplicate(NULL) gibt 0 zurueck", result == 0);
}
// Test 10: Fehlerbehandlung - Zu kleine Länge
void test_get_duplicate_too_small()
{
printf(BLUE "\n--- Test 10: Fehlerbehandlung zu kleine Laenge ---" RESET "\n");
unsigned int testArray[] = {42};
unsigned int result = getDuplicate(testArray, 1);
printTestResult("getDuplicate mit len=1 gibt 0 zurueck", result == 0);
}
// Test 11: Eindeutigkeit - Verschiedene Runs erzeugen verschiedene Arrays
void test_randomness()
{
printf(BLUE "\n--- Test 11: Zufaelligkeit ---" RESET "\n");
unsigned int len = 10;
unsigned int *numbers1 = createNumbers(len);
unsigned int *numbers2 = createNumbers(len);
if (numbers1 == NULL || numbers2 == NULL)
{
printTestResult("Arrays konnten erstellt werden", 0);
free(numbers1);
free(numbers2);
return;
}
// Prüfe ob Arrays unterschiedlich sind
int different = 0;
for (unsigned int i = 0; i < len; i++)
{
if (numbers1[i] != numbers2[i])
{
different = 1;
break;
}
}
printTestResult("Zwei Aufrufe erzeugen unterschiedliche Arrays", different);
free(numbers1);
free(numbers2);
}
// Test 12: Stress-Test
void test_stress()
{
printf(BLUE "\n--- Test 12: Stress-Test (500 Zahlen) ---" RESET "\n");
unsigned int len = 500;
unsigned int *numbers = createNumbers(len);
printTestResult("createNumbers(500) erfolgreich", numbers != NULL);
if (numbers != NULL)
{
unsigned int duplicate = getDuplicate(numbers, len);
int occurrences = countOccurrences(numbers, len, duplicate);
printTestResult("getDuplicate findet Duplikat in grossem Array", occurrences == 2);
free(numbers);
}
}
int main()
{
// Zufallsgenerator EINMAL zu Beginn initialisieren
srand(time(NULL));
printf("\n");
printf("+----------------------------------------------+\n");
printf("| NUMBERS UNIT TESTS |\n");
printf("+----------------------------------------------+\n");
test_create_numbers_small();
test_create_numbers_medium();
test_create_numbers_minimum();
test_create_numbers_large();
test_get_duplicate_finds_duplicate();
test_get_duplicate_sorted();
test_get_duplicate_unsorted();
test_integration_create_and_get();
test_get_duplicate_null();
test_get_duplicate_too_small();
test_randomness();
test_stress();
printf("\n");
printf("+----------------------------------------------+\n");
printf("| TEST ZUSAMMENFASSUNG |\n");
printf("+----------------------------------------------+\n");
printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed);
printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed);
printf("Gesamt: %d\n", testsPassed + testsFailed);
if (testsFailed == 0)
{
printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET);
return EXIT_SUCCESS;
}
else
{
printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET);
return EXIT_FAILURE;
}
}
+276
View File
@@ -0,0 +1,276 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "stack.h"
// ANSI Farben für bessere Lesbarkeit
#define GREEN "\033[0;32m"
#define RED "\033[0;31m"
#define RESET "\033[0m"
#define BLUE "\033[0;34m"
int testsPassed = 0;
int testsFailed = 0;
void printTestResult(const char *testName, int passed)
{
if (passed)
{
printf(GREEN "[PASS]" RESET " %s\n", testName);
testsPassed++;
}
else
{
printf(RED "[FAIL]" RESET " %s\n", testName);
testsFailed++;
}
}
// Test 1: Push und Top
void test_push_and_top()
{
printf(BLUE "\n--- Test 1: Push und Top ---" RESET "\n");
StackNode *stack = NULL;
int value1 = 42;
int value2 = 17;
// Erstes Element pushen
stack = push(stack, &value1);
int *topValue = (int *)top(stack);
printTestResult("Push eines Elements", stack != NULL);
printTestResult("Top gibt korrekten Wert zurueck", topValue != NULL && *topValue == 42);
// Zweites Element pushen
stack = push(stack, &value2);
topValue = (int *)top(stack);
printTestResult("Push eines zweiten Elements", stack != NULL);
printTestResult("Top gibt neuesten Wert zurueck (LIFO)", topValue != NULL && *topValue == 17);
// Aufräumen
clearStack(stack);
}
// Test 2: Pop
void test_pop()
{
printf(BLUE "\n--- Test 2: Pop ---" RESET "\n");
StackNode *stack = NULL;
int value1 = 100;
int value2 = 200;
int value3 = 300;
// Drei Elemente pushen
stack = push(stack, &value1);
stack = push(stack, &value2);
stack = push(stack, &value3);
// Erstes Pop
int *topBefore = (int *)top(stack);
stack = pop(stack);
int *topAfter = (int *)top(stack);
printTestResult("Pop entfernt oberstes Element", topBefore != NULL && *topBefore == 300);
printTestResult("Nach Pop ist naechstes Element oben", topAfter != NULL && *topAfter == 200);
// Zweites Pop
stack = pop(stack);
topAfter = (int *)top(stack);
printTestResult("Nach zweitem Pop ist letztes Element oben", topAfter != NULL && *topAfter == 100);
// Letztes Pop
stack = pop(stack);
printTestResult("Nach letztem Pop ist Stack leer", stack == NULL);
// Pop auf leerem Stack
stack = pop(stack);
printTestResult("Pop auf leerem Stack gibt NULL zurueck", stack == NULL);
}
// Test 3: Top auf leerem Stack
void test_top_empty_stack()
{
printf(BLUE "\n--- Test 3: Top auf leerem Stack ---" RESET "\n");
StackNode *stack = NULL;
void *result = top(stack);
printTestResult("Top auf leerem Stack gibt NULL zurueck", result == NULL);
}
// Test 4: ClearStack
void test_clear_stack()
{
printf(BLUE "\n--- Test 4: ClearStack ---" RESET "\n");
StackNode *stack = NULL;
int values[5] = {10, 20, 30, 40, 50};
// Mehrere Elemente pushen
for (int i = 0; i < 5; i++)
{
stack = push(stack, &values[i]);
}
printTestResult("Stack wurde mit 5 Elementen gefuellt", stack != NULL);
// Stack löschen
clearStack(stack);
stack = NULL;
printTestResult("ClearStack wurde ausgefuehrt (manuell pruefen mit valgrind)", 1);
// Neuer Push nach Clear
int newValue = 999;
stack = push(stack, &newValue);
int *topValue = (int *)top(stack);
printTestResult("Nach Clear kann neuer Stack aufgebaut werden", topValue != NULL && *topValue == 999);
clearStack(stack);
}
// Test 5: LIFO-Prinzip mit mehreren Elementen
void test_lifo_principle()
{
printf(BLUE "\n--- Test 5: LIFO-Prinzip ---" RESET "\n");
StackNode *stack = NULL;
int values[10];
// 10 Elemente in aufsteigender Reihenfolge pushen
for (int i = 0; i < 10; i++)
{
values[i] = i;
stack = push(stack, &values[i]);
}
// In umgekehrter Reihenfolge poppen und prüfen
int allCorrect = 1;
for (int i = 9; i >= 0; i--)
{
int *topValue = (int *)top(stack);
if (topValue == NULL || *topValue != i)
{
allCorrect = 0;
break;
}
stack = pop(stack);
}
printTestResult("LIFO-Prinzip: Elemente kommen in umgekehrter Reihenfolge zurueck", allCorrect);
printTestResult("Nach allen Pops ist Stack leer", stack == NULL);
}
// Test 6: Push mit verschiedenen Datentypen
void test_different_data_types()
{
printf(BLUE "\n--- Test 6: Verschiedene Datentypen ---" RESET "\n");
StackNode *stack = NULL;
// Integer
int intVal = 42;
stack = push(stack, &intVal);
// Double
double doubleVal = 3.14159;
stack = push(stack, &doubleVal);
// String
char *stringVal = "Hello Stack!";
stack = push(stack, &stringVal);
// Rückwärts prüfen
char **topString = (char **)top(stack);
stack = pop(stack);
double *topDouble = (double *)top(stack);
stack = pop(stack);
int *topInt = (int *)top(stack);
stack = pop(stack);
int stringCorrect = (topString != NULL && strcmp(*topString, "Hello Stack!") == 0);
int doubleCorrect = (topDouble != NULL && *topDouble > 3.14 && *topDouble < 3.15);
int intCorrect = (topInt != NULL && *topInt == 42);
printTestResult("Stack funktioniert mit String", stringCorrect);
printTestResult("Stack funktioniert mit Double", doubleCorrect);
printTestResult("Stack funktioniert mit Integer", intCorrect);
clearStack(stack);
}
// Test 7: Stress-Test mit vielen Elementen
void test_large_stack()
{
printf(BLUE "\n--- Test 7: Stress-Test (1000 Elemente) ---" RESET "\n");
StackNode *stack = NULL;
int *values = malloc(1000 * sizeof(int));
// 1000 Elemente pushen
for (int i = 0; i < 1000; i++)
{
values[i] = i;
stack = push(stack, &values[i]);
}
// Prüfe Top
int *topValue = (int *)top(stack);
printTestResult("1000 Elemente gepusht, Top ist korrekt", topValue != NULL && *topValue == 999);
// Alle wieder poppen
int count = 0;
while (stack != NULL)
{
stack = pop(stack);
count++;
}
printTestResult("Alle 1000 Elemente erfolgreich gepoppt", count == 1000);
free(values);
}
int main()
{
printf("\n");
printf("+----------------------------------------------+\n");
printf("| STACK UNIT TESTS |\n");
printf("+----------------------------------------------+\n");
test_push_and_top();
test_pop();
test_top_empty_stack();
test_clear_stack();
test_lifo_principle();
test_different_data_types();
test_large_stack();
printf("\n");
printf("+----------------------------------------------+\n");
printf("| TEST ZUSAMMENFASSUNG |\n");
printf("+----------------------------------------------+\n");
printf(GREEN "Tests bestanden: %d" RESET "\n", testsPassed);
printf(RED "Tests fehlgeschlagen: %d" RESET "\n", testsFailed);
printf("Gesamt: %d\n", testsPassed + testsFailed);
if (testsFailed == 0)
{
printf(GREEN "\n==> Alle Tests erfolgreich!\n" RESET);
return EXIT_SUCCESS;
}
else
{
printf(RED "\n==> Einige Tests sind fehlgeschlagen!\n" RESET);
return EXIT_FAILURE;
}
}
+138
View File
@@ -0,0 +1,138 @@
#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. */
// 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)
{
// Basisfall: Leerer Baum -> neuen Knoten erstellen
if (root == NULL)
{
TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
if (newNode == NULL)
return NULL;
// Datenkopie erstellen
newNode->data = malloc(dataSize);
if (newNode->data == NULL)
{
free(newNode);
return NULL;
}
memcpy(newNode->data, data, dataSize);
newNode->left = NULL;
newNode->right = NULL;
// Neues Element wurde hinzugefügt
if (isDuplicate != NULL)
*isDuplicate = 0;
return newNode;
}
// Rekursiver Fall: Vergleiche mit aktuellem Knoten
int cmp = compareFct(data, root->data);
if (cmp < 0)
{
// Kleiner -> links einfügen
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
}
else if (cmp > 0)
{
// Größer -> rechts einfügen
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
else
{
// Gleich -> Duplikat gefunden
if (isDuplicate != NULL)
{
*isDuplicate = 1; // Duplikat erkannt
// Nichts einfügen, nur isDuplicate setzen
}
else
{
// Duplikate erlaubt -> füge rechts ein
root->right = addToTree(root->right, data, dataSize, compareFct, NULL);
}
}
return root;
}
// Statischer Stack für nextTreeData (wie bei strtok)
static StackNode *iteratorStack = NULL;
// 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.
void *nextTreeData(TreeNode *root)
{
// Neuer Durchlauf: Stack leeren und initialisieren
if (root != NULL)
{
clearStack(iteratorStack);
iteratorStack = NULL;
// Wurzel und alle linken Knoten auf den Stack
TreeNode *current = root;
while (current != NULL)
{
iteratorStack = push(iteratorStack, current);
current = current->left;
}
}
// Stack leer -> keine weiteren Elemente
if (iteratorStack == NULL)
return NULL;
// Obersten Knoten vom Stack holen
TreeNode *node = (TreeNode *)top(iteratorStack);
iteratorStack = pop(iteratorStack);
// Rechten Teilbaum vorbereiten (alle linken Knoten auf Stack)
TreeNode *current = node->right;
while (current != NULL)
{
iteratorStack = push(iteratorStack, current);
current = current->left;
}
return node->data;
}
// Releases all memory resources (including data copies).
void clearTree(TreeNode *root)
{
if (root == NULL)
return;
// Post-Order: Links -> Rechts -> Wurzel
clearTree(root->left);
clearTree(root->right);
// Datenkopie freigeben
free(root->data);
// Knoten freigeben
free(root);
}
// Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root)
{
if (root == NULL)
return 0;
// Rekursiv: 1 (aktueller Knoten) + linker Teilbaum + rechter Teilbaum
return 1 + treeSize(root->left) + treeSize(root->right);
}
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
View File
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "numbers.h"
#include "timer.h"
#include "highscore.h"
@@ -39,6 +40,9 @@ int main(int argc, char *argv[])
{
int exitCode = EXIT_FAILURE;
// Zufallsgenerator EINMAL initialisieren
srand(time(NULL));
if(argc != 2)
{
fprintf(stderr, "Usage: %s <player name>\n", argv[0]);
+1 -1
View File
@@ -29,7 +29,7 @@ program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble
$(program_obj_files): %.o: %.c
$(program_obj_filesobj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
File renamed without changes.
File renamed without changes.
File renamed without changes.
+112
View File
@@ -0,0 +1,112 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
* Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
static int compareUnsignedInt(const void *arg1, const void *arg2)
{
unsigned int val1 = *(const unsigned int *)arg1;
unsigned int val2 = *(const unsigned int *)arg2;
if (val1 < val2)
return -1;
else if (val1 > val2)
return 1;
else
return 0;
}
// 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 < 1)
return NULL;
// Array allokieren
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (numbers == NULL)
return NULL;
// Binärbaum für Duplikaterkennung
TreeNode *tree = NULL;
// len verschiedene Zufallszahlen erzeugen (zwischen 1 und 2*len)
for (unsigned int i = 0; i < len; i++)
{
unsigned int randomNum;
int isDuplicate;
// Wiederhole, bis eine neue (nicht-doppelte) Zahl gefunden wird
do
{
isDuplicate = 0;
randomNum = (rand() % (2 * len)) + 1; // Zahlen zwischen 1 und 2*len
// Versuche in Baum einzufügen und prüfe auf Duplikat
tree = addToTree(tree, &randomNum, sizeof(unsigned int), compareUnsignedInt, &isDuplicate);
} while (isDuplicate == 1);
numbers[i] = randomNum;
}
// Baum freigeben
clearTree(tree);
// Zufälligen Index wählen und diesen Wert duplizieren
unsigned int duplicateIndex = rand() % len;
unsigned int duplicateValue = numbers[duplicateIndex];
// Einen anderen zufälligen Index finden, um das Duplikat einzufügen
unsigned int targetIndex;
do
{
targetIndex = rand() % len;
} while (targetIndex == duplicateIndex);
// Duplikat einfügen
numbers[targetIndex] = duplicateValue;
return numbers;
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
if (numbers == NULL || len < 2)
return 0;
// Kopie des Arrays erstellen (da qsort das Original verändert)
unsigned int *sortedNumbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (sortedNumbers == NULL)
return 0;
memcpy(sortedNumbers, numbers, len * sizeof(unsigned int));
// Array sortieren
qsort(sortedNumbers, len, sizeof(unsigned int), compareUnsignedInt);
// Benachbarte Elemente vergleichen
unsigned int duplicate = 0;
for (unsigned int i = 0; i < len - 1; i++)
{
if (sortedNumbers[i] == sortedNumbers[i + 1])
{
duplicate = sortedNumbers[i];
break;
}
}
// Speicher freigeben
free(sortedNumbers);
return duplicate;
}
View File
File renamed without changes.
+80
View File
@@ -0,0 +1,80 @@
@echo off
REM Alle Tests ausführen (Windows Version)
echo ================================================
echo DOBLE - Alle Unit Tests ausfuehren
echo ================================================
echo.
REM Test 1: Stack
echo ================================================
echo 1. STACK TESTS
echo ================================================
gcc -g -Wall -o test_stack.exe Test_stack.c stack.c
if %ERRORLEVEL% EQU 0 (
test_stack.exe
set STACK_RESULT=%ERRORLEVEL%
) else (
echo Fehler: Stack Tests konnten nicht kompiliert werden
set STACK_RESULT=1
)
echo.
REM Test 2: Binärbaum
echo ================================================
echo 2. BINAERBAUM TESTS
echo ================================================
gcc -g -Wall -o test_bintree.exe Test_bintree.c bintree.c stack.c
if %ERRORLEVEL% EQU 0 (
test_bintree.exe
set BINTREE_RESULT=%ERRORLEVEL%
) else (
echo Fehler: Binaerbaum Tests konnten nicht kompiliert werden
set BINTREE_RESULT=1
)
echo.
REM Test 3: Numbers
echo ================================================
echo 3. NUMBERS TESTS
echo ================================================
gcc -g -Wall -o test_numbers.exe Test_numbers.c numbers.c bintree.c stack.c -lm
if %ERRORLEVEL% EQU 0 (
test_numbers.exe
set NUMBERS_RESULT=%ERRORLEVEL%
) else (
echo Fehler: Numbers Tests konnten nicht kompiliert werden
set NUMBERS_RESULT=1
)
echo.
REM Zusammenfassung
echo ================================================
echo GESAMTERGEBNIS
echo ================================================
if %STACK_RESULT% EQU 0 (
echo [OK] Stack Tests: BESTANDEN
) else (
echo [FEHLER] Stack Tests: FEHLGESCHLAGEN
)
if %BINTREE_RESULT% EQU 0 (
echo [OK] Binaerbaum Tests: BESTANDEN
) else (
echo [FEHLER] Binaerbaum Tests: FEHLGESCHLAGEN
)
if %NUMBERS_RESULT% EQU 0 (
echo [OK] Numbers Tests: BESTANDEN
) else (
echo [FEHLER] Numbers Tests: FEHLGESCHLAGEN
)
echo.
if %STACK_RESULT% EQU 0 if %BINTREE_RESULT% EQU 0 if %NUMBERS_RESULT% EQU 0 (
echo ALLE TESTS ERFOLGREICH!
) else (
echo Einige Tests sind fehlgeschlagen
)
pause
+16
View File
@@ -0,0 +1,16 @@
@echo off
REM Binaerbaum Tests kompilieren und ausfuehren
echo === Binaerbaum Tests kompilieren ===
gcc -g -Wall -o test_bintree.exe Test_bintree.c bintree.c stack.c
if %ERRORLEVEL% EQU 0 (
echo Kompilierung erfolgreich!
echo.
echo === Binaerbaum Tests ausfuehren ===
test_bintree.exe
) else (
echo Kompilierung fehlgeschlagen!
)
pause
+16
View File
@@ -0,0 +1,16 @@
@echo off
REM Numbers Tests kompilieren und ausfuehren
echo === Numbers Tests kompilieren ===
gcc -g -Wall -o test_numbers.exe Test_numbers.c numbers.c bintree.c stack.c -lm
if %ERRORLEVEL% EQU 0 (
echo Kompilierung erfolgreich!
echo.
echo === Numbers Tests ausfuehren ===
test_numbers.exe
) else (
echo Kompilierung fehlgeschlagen!
)
pause
+16
View File
@@ -0,0 +1,16 @@
@echo off
REM Stack Tests kompilieren und ausfuehren
echo === Stack Tests kompilieren ===
gcc -g -Wall -o test_stack.exe Test_stack.c stack.c
if %ERRORLEVEL% EQU 0 (
echo Kompilierung erfolgreich!
echo.
echo === Stack Tests ausfuehren ===
test_stack.exe
) else (
echo Kompilierung fehlgeschlagen!
)
pause
+57
View File
@@ -0,0 +1,57 @@
#include <stdlib.h>
#include "stack.h"
//TODO: grundlegende Stackfunktionen implementieren:
/* * `push`: legt ein Element oben auf den Stack,
* `pop`: entfernt das oberste Element,
* `top`: liefert das oberste Element zurück,
* `clearStack`: gibt den gesamten Speicher frei. */
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
// Neuen Knoten erstellen
StackNode *newNode = (StackNode *)malloc(sizeof(StackNode));
if (newNode == NULL)
return stack; // Bei Fehler: alter Stack zurück
// Daten eintragen
newNode->data = data;
newNode->next = stack; // Alter Stack wird zum "nächsten" Element
return newNode; // Neuer Knoten ist jetzt oben
}
// 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)
{
if (stack == NULL)
return NULL; // Leerer Stack
StackNode *nextNode = stack->next; // Merke dir das nächste Element
free(stack); // Gib den obersten Knoten frei
return nextNode; // Nächstes Element ist jetzt oben
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
if (stack == NULL)
return NULL; // Leerer Stack
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
while (stack != NULL)
{
StackNode *next = stack->next; // Merke dir das nächste Element
free(stack); // Gib aktuellen Knoten frei
stack = next; // Gehe zum nächsten
}
}
+5 -1
View File
@@ -8,7 +8,11 @@ The latest element is taken from the stack. */
#include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen
typedef struct StackNode
{
void *data; // Zeiger auf die gespeicherten Daten
struct StackNode *next; // Zeiger auf das nächste Element im Stack
} StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data);
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.