Template
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5af439e99 |
No files matched your search
-62
@@ -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.
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
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.
@@ -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]);
|
||||
@@ -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.
@@ -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;
|
||||
}
|
||||
File renamed without changes.
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
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.
Reference in new issue
Block a user