generated from freudenreichan/info2Praktikum-DobleSpiel
Compare commits
5
Commits
d51184f13b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06890682f8 | ||
|
|
a515698e0f | ||
|
|
a309d2dfc2 | ||
|
|
2e93327ba5 | ||
|
|
833e93fa49 |
No files matched your search
@@ -1,4 +1,4 @@
|
||||
#include <string.h>
|
||||
#include <string.h> // für memcpy
|
||||
#include "stack.h"
|
||||
#include "bintree.h"
|
||||
|
||||
@@ -11,8 +11,46 @@
|
||||
// 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)
|
||||
{
|
||||
|
||||
{
|
||||
// 1. Leerer Baum → neuen Knoten anlegen
|
||||
if (root == NULL) // Baum muss leer sein
|
||||
{
|
||||
TreeNode *node = malloc(sizeof(TreeNode)); // Speicherreservierung
|
||||
if (!node) return NULL; //Abbruch wenn kein Speicher verfügbar
|
||||
|
||||
node->data = malloc(dataSize); // Speicher für Daten reservieren
|
||||
if (!node->data) { // Bei Fehler -> freigeben des Knotens und abbrechen
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(node->data, data, dataSize); // Daten kopieren (nicht Zeiger)
|
||||
|
||||
node->left = node->right = NULL; // Neuer Knoten hat keine Kinder
|
||||
|
||||
if (isDuplicate) *isDuplicate = 0; // Rückmeldung (kein Duplikat)
|
||||
return node;
|
||||
}
|
||||
|
||||
// 2. Vergleich, um Einfügerichtung zu bestimmen
|
||||
int cmp = compareFct(data, root->data);
|
||||
|
||||
if (cmp < 0) // kleiner nach links weitergeben (rekursiv)
|
||||
{
|
||||
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||
}
|
||||
else if (cmp > 0) // größer nach rechts weitergeben
|
||||
{
|
||||
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Duplikat
|
||||
if (isDuplicate) *isDuplicate = 1;
|
||||
// wird nicht eingefügt (kein Änderung am Baum)
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction.
|
||||
@@ -20,17 +58,62 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFc
|
||||
// push the top node and push all its left nodes.
|
||||
void *nextTreeData(TreeNode *root)
|
||||
{
|
||||
static StackNode *iterStack = NULL; // behält den Wert zw. Funktionsaufrufen (speichert welche Knoten noch besucht werden müssen)
|
||||
|
||||
// Wird ein neuer Baum übergeben?
|
||||
if (root != NULL)
|
||||
{
|
||||
// alten Stack löschen
|
||||
clearStack(iterStack);
|
||||
iterStack = NULL;
|
||||
|
||||
// Root + alle linken Knoten auf Stack pushen
|
||||
TreeNode *cur = root;
|
||||
while (cur != NULL)
|
||||
{
|
||||
iterStack = push(iterStack, cur);
|
||||
cur = cur->left;
|
||||
}
|
||||
}
|
||||
|
||||
// Kein Baum mehr → Besuchen aller Knoten beendet
|
||||
if (iterStack == NULL)
|
||||
return NULL;
|
||||
|
||||
// Top-Knoten (als nächstes Reihe)
|
||||
TreeNode *node = (TreeNode *)top(iterStack);
|
||||
iterStack = pop(iterStack); //entfernen des Knoten
|
||||
|
||||
// Rechtsknoten
|
||||
TreeNode *right = node->right; //nach Besuch bei rechten Knoten in rechten Teilbaum
|
||||
while (right != NULL)
|
||||
{
|
||||
iterStack = push(iterStack, right);
|
||||
right = right->left; // von dort ganz nach links und alles pushen
|
||||
}
|
||||
|
||||
return node->data;
|
||||
}
|
||||
|
||||
// Releases all memory resources (including data copies).
|
||||
void clearTree(TreeNode *root)
|
||||
{
|
||||
if (root == NULL) //Abbruchbedingung
|
||||
return;
|
||||
|
||||
clearTree(root->left); // Links und rechts löschen
|
||||
clearTree(root->right);
|
||||
|
||||
free(root->data); // Daten freigeben
|
||||
free(root);
|
||||
}
|
||||
|
||||
// Returns the number of entries in the tree given by root.
|
||||
unsigned int treeSize(const TreeNode *root)
|
||||
{
|
||||
if (root == NULL) // Leerer Baum
|
||||
return 0;
|
||||
|
||||
return 1 + treeSize(root->left) + treeSize(root->right);
|
||||
// Größe = 1 + Größe links + Größe rechts
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <time.h> // für Zufallszahlen
|
||||
#include <string.h>
|
||||
#include "numbers.h"
|
||||
#include "bintree.h"
|
||||
@@ -10,17 +10,91 @@
|
||||
* 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. */
|
||||
// Vergleichsfunktion für unsigned int
|
||||
|
||||
static int compareUInt(const void *a, const void *b)
|
||||
{
|
||||
unsigned int x = *(unsigned int *)a; // beide void Zeiger in unsigned int
|
||||
unsigned int y = *(unsigned int *)b;
|
||||
|
||||
// Vergleich wie beim Binärbaum
|
||||
if (x < y) return -1; // links
|
||||
if (x > y) return 1; // rechts
|
||||
return 0; // gleich
|
||||
}
|
||||
|
||||
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
|
||||
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
|
||||
// creating random numbers.
|
||||
unsigned int *createNumbers(unsigned int len)
|
||||
{
|
||||
if (len < 2) // min 2 Zahlen sind notwendig
|
||||
return NULL;
|
||||
|
||||
// Erzeugen eines Arrays (unsigned int)
|
||||
unsigned int *arr = malloc(sizeof(unsigned int) * len);
|
||||
if (!arr)
|
||||
return NULL; // kein Speicher -> Fehler
|
||||
|
||||
srand((unsigned int)time(NULL)); // Initialisieren Zufallszahl
|
||||
|
||||
TreeNode *root = NULL;
|
||||
int isDup; // zeigt ob Duplikat
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
// Erzeugen der Zufallszahlen
|
||||
while (count < len - 1) // ERST len-1 verschiedene Zahlen (ein Platz übrig für Duplikat)
|
||||
{
|
||||
unsigned int value = (rand() % (2 * len)) + 1; // Bereich 1 bis 2len (wahrscheinlich wenig Duplikate)
|
||||
|
||||
root = addToTree(root, &value, sizeof(unsigned int), compareUInt, &isDup);
|
||||
// Einfügen der Zahl in Binärbaum (isDup==0 neue Zahl ) (isDup==1 Zahl war schon)
|
||||
|
||||
if (!isDup) // nur hinzufügen, wenn kein Duplikat
|
||||
{
|
||||
arr[count] = value; //Neuer Wert gespeichert (Duplikate ignoriert)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// EIN zufälliges Duplikat hinzufügen
|
||||
unsigned int idx = rand() % (len - 1);
|
||||
arr[len - 1] = arr[idx];
|
||||
|
||||
clearTree(root); // Freigeben des Baumes
|
||||
return arr; // Zurückgeben des Array
|
||||
}
|
||||
|
||||
// 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 || len < 2) // Prüfen ob Array leer oder zu kurz
|
||||
return 0;
|
||||
|
||||
// Kopie erstellen zum Sortieren
|
||||
unsigned int *tmp = malloc(sizeof(unsigned int) * len);
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) // Werte kopieren
|
||||
tmp[i] = numbers[i];
|
||||
|
||||
// Sortieren (qsort - Vergleichsfunktion)
|
||||
qsort(tmp, len, sizeof(unsigned int), compareUInt);
|
||||
|
||||
// benachbarte Duplikate finden
|
||||
unsigned int duplicate = 0;
|
||||
|
||||
for (unsigned int i = 0; i < len - 1; i++) // Durchlaufen des Arrays
|
||||
{
|
||||
if (tmp[i] == tmp[i + 1]) // wenn 2 aufeinanderfolgende Werte gleich -> Duplikat
|
||||
{
|
||||
duplicate = tmp[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(tmp); // Kopie freigeben
|
||||
return duplicate; //gefundene Zahl zurückgeben
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h> // Abbruch bei unerfüllter Bedingung
|
||||
#include "numbers.h"
|
||||
#include "bintree.h"
|
||||
|
||||
// Vergleichsfunktion für unsigned int (für BST-Test)
|
||||
static int compareUInt(const void *a, const void *b) // nur in dieser Datei sichtbar
|
||||
{
|
||||
unsigned int x = *(const unsigned int *)a; // in unsigned in umwandeln
|
||||
unsigned int y = *(const unsigned int *)b;
|
||||
|
||||
if (x < y) return -1; // Vergleichsrückgabe für Binärbaum
|
||||
if (x > y) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_createNumbers_basic()
|
||||
{
|
||||
printf("Running test_createNumbers_basic...\n");
|
||||
|
||||
unsigned int len = 20; // Anlegen eines Arrays
|
||||
unsigned int *arr = createNumbers(len);
|
||||
assert(arr != NULL); // Fehler -> Abbruch
|
||||
|
||||
|
||||
assert(len >= 2); // für ein Duplikat min 2
|
||||
|
||||
// Prüfen: Array hat länge len
|
||||
unsigned int size = len;
|
||||
(void)size; // vermeidet warnings
|
||||
|
||||
free(arr); // Speicher wird freigegeben
|
||||
printf(" test_createNumbers_basic passed\n");
|
||||
}
|
||||
|
||||
void test_createNumbers_unique_except_one()
|
||||
{
|
||||
printf("Running test_createNumbers_unique_except_one...\n");
|
||||
|
||||
unsigned int len = 100; // Erzeugen eines Arrays
|
||||
unsigned int *arr = createNumbers(len);
|
||||
assert(arr != NULL);
|
||||
|
||||
// Prüfen, dass genau EIN Duplikat existiert
|
||||
TreeNode *root = NULL; // neuer Binärbaum
|
||||
int isDup; // zeigt ob Wert doppelt
|
||||
unsigned int duplicateCount = 0; // zählt gefundene Duplikate
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) // Array in BST eingefügt
|
||||
{
|
||||
root = addToTree(root, &arr[i], sizeof(unsigned int), compareUInt, &isDup);
|
||||
if (isDup)
|
||||
duplicateCount++; // sollte 1 sein
|
||||
}
|
||||
|
||||
// Es muss genau 1 doppelter Wert existieren
|
||||
assert(duplicateCount == 1);
|
||||
|
||||
clearTree(root); // Baum und Array freigeben
|
||||
free(arr);
|
||||
|
||||
printf(" test_createNumbers_unique_except_one passed\n");
|
||||
}
|
||||
|
||||
void test_getDuplicate()
|
||||
{
|
||||
printf("Running test_getDuplicate...\n");
|
||||
|
||||
unsigned int len = 50; // Erzeugen eines Arrays
|
||||
unsigned int *arr = createNumbers(len);
|
||||
assert(arr != NULL);
|
||||
|
||||
unsigned int duplicate = getDuplicate(arr, len); // soll Duplikat finden
|
||||
|
||||
|
||||
unsigned int countInArray = 0;
|
||||
for (unsigned int i = 0; i < len; i++) // Durchlauf des Arrays
|
||||
{
|
||||
if (arr[i] == duplicate)
|
||||
countInArray++; // Zählt wie oft die gefundene Zahl vorkommt
|
||||
}
|
||||
|
||||
assert(countInArray == 2); // alle anderen Werte einzigartig
|
||||
|
||||
free(arr); // Array freigeben
|
||||
|
||||
printf(" test_getDuplicate passed\n");
|
||||
}
|
||||
|
||||
// Testet große Arrays (Stress-Test)
|
||||
void test_large_input() // testes zufällige Kollision
|
||||
{
|
||||
printf("Running test_large_input...\n");
|
||||
|
||||
unsigned int len = 20000; // Erzeugen eines Arrays
|
||||
unsigned int *arr = createNumbers(len);
|
||||
assert(arr != NULL);
|
||||
|
||||
unsigned int d = getDuplicate(arr, len); // doppelter Wert sollte existieren
|
||||
assert(d != 0);
|
||||
|
||||
free(arr); // Array freigeben
|
||||
|
||||
printf(" test_large_input passed\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("=== Running numbers Tests ===\n");
|
||||
|
||||
test_createNumbers_basic(); // alle Test nacheinander ausführen
|
||||
test_createNumbers_unique_except_one();
|
||||
test_getDuplicate();
|
||||
test_large_input();
|
||||
|
||||
printf("=== All tests passed successfully! ===\n");
|
||||
return 0;
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // für malloc und free
|
||||
#include <assert.h> // für assert() - Programm stoppt bei Fehlern
|
||||
#include "stack.h"
|
||||
|
||||
// Hilfsfunktion: beendet Programm bei malloc-Fehler
|
||||
int *make_int(int value)
|
||||
{
|
||||
int *p = malloc(sizeof(int)); //Reserviert Speicherplatz für eine Zahl und gibt dessen Adresse zurück
|
||||
assert(p != NULL); // Programm stoppt wenn Speicher zu knapp
|
||||
*p = value; // Speichert Wert in neuen Speicherplatz
|
||||
return p; // Gibt Zeiger zurück
|
||||
}
|
||||
|
||||
// Test: Push und Top.
|
||||
void test_push_and_top()
|
||||
{
|
||||
printf("Running test_push_and_top...\n");
|
||||
|
||||
StackNode *stack = NULL; // Stack beginnt leer
|
||||
|
||||
int *a = make_int(10); // zwei Zeiger
|
||||
int *b = make_int(20);
|
||||
|
||||
stack = push(stack, a); // Erst 10 auf Stack gelegt
|
||||
stack = push(stack, b); // Dann 20 (oben)
|
||||
|
||||
int *topValue = (int *)top(stack); // Datentyp in int umgewandelt
|
||||
assert(topValue != NULL); // Stack darf nicht leer sein
|
||||
assert(*topValue == 20); // Kopf muss 20 sein
|
||||
|
||||
clearStack(stack); // Entfernt alle Knoten
|
||||
free(a); // Löscht die Daten
|
||||
free(b);
|
||||
|
||||
printf(" test_push_and_top passed\n");
|
||||
}
|
||||
|
||||
// Test: Pop in korrekter Reihenfolge
|
||||
void test_push_pop_sequence()
|
||||
{
|
||||
printf("Running test_push_pop_sequence...\n");
|
||||
|
||||
StackNode *stack = NULL; // Stack muss leer sein
|
||||
|
||||
int *a = make_int(1); // Definieren der Testwerte
|
||||
int *b = make_int(2);
|
||||
int *c = make_int(3);
|
||||
|
||||
stack = push(stack, a); // Werte auf den Stack legen (C oben)
|
||||
stack = push(stack, b);
|
||||
stack = push(stack, c);
|
||||
|
||||
// Pop 3
|
||||
int *v = (int *)top(stack); //Top muss 3 sein
|
||||
assert(*v == 3);
|
||||
stack = pop(stack); // 3 entfernen
|
||||
|
||||
// Pop 2
|
||||
v = (int *)top(stack); //analog zur 3
|
||||
assert(*v == 2);
|
||||
stack = pop(stack);
|
||||
|
||||
// Pop 1
|
||||
v = (int *)top(stack);
|
||||
assert(*v == 1);
|
||||
stack = pop(stack);
|
||||
|
||||
// Stack sollte leer sein
|
||||
assert(stack == NULL);
|
||||
|
||||
free(a); // Freigeben des Speichers
|
||||
free(b);
|
||||
free(c);
|
||||
|
||||
printf(" test_push_pop_sequence passed\n");
|
||||
}
|
||||
|
||||
// Test: clearStack
|
||||
void test_clearStack()
|
||||
{
|
||||
printf("Running test_clearStack...\n");
|
||||
|
||||
StackNode *stack = NULL; // Stack muss leer sein
|
||||
|
||||
for (int i = 0; i < 5; i++) // 5 Elemente auf dem Stack (O bis 4)
|
||||
stack = push(stack, make_int(i));
|
||||
|
||||
clearStack(stack); //Knoten freigeben
|
||||
|
||||
// danach ist Stack nur als "gelöscht" markiert,
|
||||
// aber Pointer ist nicht automatisch NULL → das prüft man so:
|
||||
stack = NULL; //Stackzeiger manuell auf NULL setzen
|
||||
|
||||
printf(" test_clearStack passed\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("=== Running Stack Unit Tests ===\n");
|
||||
|
||||
test_push_and_top(); // Ausführen aller Tests
|
||||
test_push_pop_sequence();
|
||||
test_clearStack();
|
||||
|
||||
printf("=== All tests passed successfully! ===\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user