generated from freudenreichan/info2Praktikum-DobleSpiel
Compare commits
7
Commits
23dccdfd8d
...
MM_Branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3837685b21 | ||
|
|
9a9f0d6bb1 | ||
|
|
31b4b5c2c7 | ||
|
|
b3f1298149 | ||
|
|
16fa87e081 | ||
|
|
ce903c6d4f | ||
|
|
5072f82928 |
No files matched your search
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug test_stack",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_stack.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug test_numbers",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_numbers.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug test_bintree",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/test_bintree.exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "C:/ProgramData/mingw64/mingw64/bin/gdb.exe",
|
||||||
|
"preLaunchTask": "Build via Makefile"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+27
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Build via Makefile",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "mingw32-make",
|
||||||
|
"args": ["${input:target}"],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": "$gcc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"id": "target",
|
||||||
|
"type": "pickString",
|
||||||
|
"description": "Welches Makefile-Target soll gebaut werden?",
|
||||||
|
"options": ["test_stack", "test_numbers", "test_bintree", "doble", "unitTests"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -93,6 +93,11 @@ TreeNode *addToTree(TreeNode *wurzel,
|
|||||||
return wurzel;
|
return wurzel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Die Funktion gibt bei jedem Aufruf das nächste Element des Binärbaums in **Inorder-Reihenfolge**
|
||||||
|
zurück und merkt sich intern, wo sie zuletzt war.
|
||||||
|
*/
|
||||||
|
|
||||||
void *nextTreeData(TreeNode *wurzel)
|
void *nextTreeData(TreeNode *wurzel)
|
||||||
{
|
{
|
||||||
static StackNode *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg
|
static StackNode *iteratorStack = NULL; // interner Zustand über Aufrufe hinweg
|
||||||
@@ -110,8 +115,8 @@ void *nextTreeData(TreeNode *wurzel)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Nächsten Knoten holen (oberstes Stack-Element)
|
// Nächsten Knoten holen (oberstes Stack-Element)
|
||||||
TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack);
|
TreeNode *aktuellerKnoten = (TreeNode *)top(iteratorStack); //Oberstes Element zurück
|
||||||
iteratorStack = pop(iteratorStack);
|
iteratorStack = pop(iteratorStack); // entfernt Oberstes Element
|
||||||
|
|
||||||
// Falls rechter Teilbaum existiert: dessen linke Kette ablegen
|
// Falls rechter Teilbaum existiert: dessen linke Kette ablegen
|
||||||
if (aktuellerKnoten->right != NULL)
|
if (aktuellerKnoten->right != NULL)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
|
Player1;19887
|
||||||
|
Player1;19843
|
||||||
Lena;19811
|
Lena;19811
|
||||||
Lena;19702
|
Lena;19702
|
||||||
|
Player1;19578
|
||||||
player_name;9981
|
player_name;9981
|
||||||
Lena;9980
|
Lena;9980
|
||||||
Lena;9978
|
Lena;9978
|
||||||
Lena;9978
|
Lena;9978
|
||||||
Lena;9976
|
Lena;9976
|
||||||
Lena;9975
|
|
||||||
Lena;9971
|
|
||||||
Lena;9965
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -5,70 +6,135 @@
|
|||||||
#include "numbers.h"
|
#include "numbers.h"
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
// helper comparator for unsigned int for bintree
|
/**
|
||||||
|
* @brief Vergleichsfunktion für unsigned int-Werte zur Verwendung im Binärbaum.
|
||||||
|
*
|
||||||
|
* Diese Funktion wird von der Binärbaum-Implementierung genutzt, um die
|
||||||
|
* Ordnung der Knoten zu bestimmen. Sie vergleicht die dereferenzierten
|
||||||
|
* unsigned int-Werte a und b.
|
||||||
|
*
|
||||||
|
* @param a Pointer auf einen unsigned int-Wert (linker Operand)
|
||||||
|
* @param b Pointer auf einen unsigned int-Wert (rechter Operand)
|
||||||
|
* @return -1, falls *a < *b; 1, falls *a > *b; 0, falls *a == *b
|
||||||
|
*/
|
||||||
static int compareUInt(const void *a, const void *b)
|
static int compareUInt(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
unsigned int va = *(const unsigned int *)a;
|
unsigned int va = *(const unsigned int *)a;
|
||||||
unsigned int vb = *(const unsigned int *)b;
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
if(va < vb) return -1;
|
if (va < vb) return -1;
|
||||||
if(va > vb) return 1;
|
if (va > vb) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// comparator for qsort (unsigned int)
|
/**
|
||||||
|
* @brief Vergleichsfunktion für qsort() zur Sortierung von unsigned int-Arrays.
|
||||||
|
*
|
||||||
|
* @param a Pointer auf einen Arrayeintrag
|
||||||
|
* @param b Pointer auf einen Arrayeintrag
|
||||||
|
* @return -1, 0, 1 analog zu compareUInt()
|
||||||
|
*/
|
||||||
static int qsort_uint_cmp(const void *a, const void *b)
|
static int qsort_uint_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
unsigned int va = *(const unsigned int *)a;
|
unsigned int va = *(const unsigned int *)a;
|
||||||
unsigned int vb = *(const unsigned int *)b;
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
if(va < vb) return -1;
|
if (va < vb) return -1;
|
||||||
if(va > vb) return 1;
|
if (va > vb) return 1;
|
||||||
return 0;
|
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
|
* @brief Erzeugt ein Array aus len Zufallszahlen im Bereich [1 .. 2*len],
|
||||||
// creating random numbers.
|
* das genau einen duplizierten Wert enthält (d. h. len-1 eindeutige + 1 Duplikat),
|
||||||
|
* und mischt die Reihenfolge zufällig.
|
||||||
|
*
|
||||||
|
* Funktionsweise:
|
||||||
|
* - Es werden zunächst len-1 eindeutige Zufallszahlen erzeugt. Die Eindeutigkeit wird
|
||||||
|
* mithilfe eines Binärsuchbaums (BST) geprüft: addToTree() fügt die Zahl ein
|
||||||
|
* und signalisiert per isDup, ob sie bereits vorhanden war.
|
||||||
|
* - Anschließend wird eine der bereits erzeugten Zahlen zufällig ausgewählt und
|
||||||
|
* noch einmal an das Ende des Arrays geschrieben, um das geforderte Duplikat sicherzustellen.
|
||||||
|
* - Zum Schluss wird das gesamte Array mittels Fisher–Yates-Algorithmus gemischt.
|
||||||
|
*
|
||||||
|
* Fehlerbehandlung:
|
||||||
|
* - Bei len < 2 wird NULL zurückgegeben, da das Problem ein Duplikat erfordert.
|
||||||
|
* - Bei Speicher- oder Baum-Insertionsfehlern wird aufgeräumt und NULL zurückgegeben.
|
||||||
|
* Wichtig: Der Baumzeiger root wird erst nach erfolgreichem Insert aktualisiert,
|
||||||
|
* um im Fehlerfall kein bereits aufgebautes Teilbaum-Objekt zu verlieren.
|
||||||
|
*
|
||||||
|
* Randbedingungen / Annahmen:
|
||||||
|
* - addToTree(root, &val, sizeof(val), compareUInt, &isDup) setzt isDup:
|
||||||
|
* isDup == 1 bedeutet „Duplikat gefunden, Baum unverändert“,
|
||||||
|
* isDup == 0 bedeutet „neuer Wert eingefügt (oder Fehler)“.
|
||||||
|
* - Bei Speicherfehler gibt addToTree NULL zurück und isDup bleibt 0.
|
||||||
|
* - clearTree(root) darf mit NULL-Argument aufgerufen werden (No-Op).
|
||||||
|
*
|
||||||
|
* Komplexität:
|
||||||
|
* - Durchschnittlich O(len * log(len)) für die len-1 Einfügungen in den BST.
|
||||||
|
* - Shuffle in O(len).
|
||||||
|
*
|
||||||
|
* @param len Anzahl der zu erzeugenden Werte (muss >= 2 sein)
|
||||||
|
* @return Pointer auf ein Array mit len Einträgen bei Erfolg; NULL bei Fehlern
|
||||||
|
*/
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int *createNumbers(unsigned int len)
|
||||||
{
|
{
|
||||||
if(len < 2)
|
if (len < 2)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
if(numbers == NULL)
|
if (numbers == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// seed once
|
// Zufallszahlengenerator nur einmal pro Prozess initialisieren.
|
||||||
srand((unsigned int)time(NULL));
|
// Hintergrund: Wird createNumbers mehrfach schnell hintereinander gerufen,
|
||||||
|
// kann time(NULL) identische Seeds liefern und damit identische Zahlenfolgen erzeugen.
|
||||||
|
static int seeded = 0;
|
||||||
|
if (!seeded) {
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
seeded = 1;
|
||||||
|
}
|
||||||
|
|
||||||
TreeNode *root = NULL;
|
TreeNode *root = NULL;
|
||||||
unsigned int range = 2 * len;
|
unsigned int range = 2 * len;
|
||||||
// create len-1 unique numbers
|
|
||||||
for(unsigned int i = 0; i < len - 1; i++)
|
// Schritt 1: len-1 eindeutige Zufallszahlen erzeugen
|
||||||
|
for (unsigned int i = 0; i < len - 1; i++)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int isDup = 0;
|
int isDup;
|
||||||
// try until a unique number is inserted
|
|
||||||
do
|
// Wiederholen, bis eine wirklich neue Zahl eingefügt wurde
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
val = (unsigned int)(rand() % range) + 1; // [1..2*len]
|
isDup = 0; // vor jedem Insert zurücksetzen, um „alte“ Werte zu vermeiden
|
||||||
root = addToTree(root, &val, sizeof(val), compareUInt, &isDup);
|
val = (unsigned int)(rand() % range) + 1; // Wertebereich [1 .. 2*len]
|
||||||
// if addToTree returned NULL due to allocation failure, cleanup and return NULL
|
|
||||||
if(root == NULL && isDup == 0)
|
// addToTree kann bei Erfolg einen (ggf. neuen) Wurzelzeiger liefern.
|
||||||
{
|
// Zur Vermeidung eines Speicherlecks bei Fehlern zunächst in temp speichern.
|
||||||
|
TreeNode *newRoot = addToTree(root, &val, sizeof(val), compareUInt, &isDup);
|
||||||
|
|
||||||
|
if (newRoot == NULL && isDup == 0) {
|
||||||
|
// Vermutlich Speicher-/Insertionsfehler: aufräumen und abbrechen
|
||||||
free(numbers);
|
free(numbers);
|
||||||
clearTree(root);
|
clearTree(root); // root zeigt noch auf den gültigen Teilbaum
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} while(isDup);
|
|
||||||
numbers[i] = val;
|
if (!isDup) {
|
||||||
|
// Einfügen war erfolgreich und der Wert ist eindeutig.
|
||||||
|
root = newRoot;
|
||||||
|
numbers[i] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Andernfalls Duplikat: Neue Zufallszahl versuchen.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// duplicate one existing random entry
|
// Schritt 2: Eine der bestehenden Zahlen zufällig duplizieren
|
||||||
unsigned int idx = (unsigned int)(rand() % (len - 1));
|
unsigned int idx = (unsigned int)(rand() % (len - 1)); // Index im Bereich [0 .. len-2]
|
||||||
numbers[len - 1] = numbers[idx];
|
numbers[len - 1] = numbers[idx];
|
||||||
|
|
||||||
// shuffle array (Fisher-Yates)
|
// Schritt 3: Fisher–Yates-Shuffle über das gesamte Array
|
||||||
for(unsigned int i = len - 1; i > 0; i--)
|
for (unsigned int i = len - 1; i > 0; i--)
|
||||||
{
|
{
|
||||||
unsigned int j = (unsigned int)(rand() % (i + 1));
|
unsigned int j = (unsigned int)(rand() % (i + 1));
|
||||||
unsigned int tmp = numbers[i];
|
unsigned int tmp = numbers[i];
|
||||||
@@ -76,31 +142,53 @@ unsigned int *createNumbers(unsigned int len)
|
|||||||
numbers[j] = tmp;
|
numbers[j] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// free tree resources
|
// Aufräumen: Baum freigeben
|
||||||
clearTree(root);
|
clearTree(root);
|
||||||
return numbers;
|
return numbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
/**
|
||||||
|
* @brief Findet den einzigen duplizierten Wert in einem Array aus len unsigned int.
|
||||||
|
*
|
||||||
|
* Funktionsweise:
|
||||||
|
* - Es wird eine Kopie des Eingabearrays erstellt, um die Reihenfolge des
|
||||||
|
* Originalarrays nicht zu verändern.
|
||||||
|
* - Die Kopie wird mittels qsort() aufsteigend sortiert.
|
||||||
|
* - Beim Durchlauf werden benachbarte Elemente verglichen. Da genau ein Wert
|
||||||
|
* doppelt vorkommt, finden wir ihn als erstes Paar gleicher Nachbarn.
|
||||||
|
*
|
||||||
|
* Fehlerbehandlung:
|
||||||
|
* - Bei ungültigen Parametern (numbers == NULL oder len < 2) wird 0 geliefert.
|
||||||
|
* - Bei Speicherfehlern beim Kopieren ebenfalls 0.
|
||||||
|
*
|
||||||
|
* Komplexität:
|
||||||
|
* - Sortieren in O(len * log(len)), anschließender Linearpass O(len).
|
||||||
|
*
|
||||||
|
* @param numbers Pointer auf das Eingabearray
|
||||||
|
* @param len Länge des Arrays (muss >= 2 sein)
|
||||||
|
* @return Der doppelte Wert; 0 bei Fehlern oder falls kein Duplikat gefunden wurde
|
||||||
|
* (gemäß Aufgabenstellung sollte aber genau ein Duplikat existieren).
|
||||||
|
*/
|
||||||
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
||||||
{
|
{
|
||||||
if(numbers == NULL || len < 2)
|
if (numbers == NULL || len < 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// make a copy so original array order is not modified by caller expectation
|
// Kopie erstellen, damit das Original unangetastet bleibt
|
||||||
unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
if(copy == NULL)
|
if (copy == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memcpy(copy, numbers, sizeof(unsigned int) * len);
|
memcpy(copy, numbers, sizeof(unsigned int) * len);
|
||||||
|
|
||||||
|
// Sortieren der Kopie
|
||||||
qsort(copy, len, sizeof(unsigned int), qsort_uint_cmp);
|
qsort(copy, len, sizeof(unsigned int), qsort_uint_cmp);
|
||||||
|
|
||||||
|
// Linearer Scan: erstes Paar identischer Nachbarn ist das Duplikat
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
for(unsigned int i = 0; i + 1 < len; i++)
|
for (unsigned int i = 0; i + 1 < len; i++)
|
||||||
{
|
{
|
||||||
if(copy[i] == copy[i+1])
|
if (copy[i] == copy[i + 1]) {
|
||||||
{
|
|
||||||
result = copy[i];
|
result = copy[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -108,4 +196,4 @@ unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
|||||||
|
|
||||||
free(copy);
|
free(copy);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
|
|
||||||
// Pushes data as pointer onto the stack.
|
// Push Daten auf den Stack legen.
|
||||||
StackNode *push(StackNode *stack, void *data)
|
StackNode *push(StackNode *stack, void *data)
|
||||||
{
|
{
|
||||||
StackNode *node = (StackNode *)malloc(sizeof(StackNode));
|
StackNode *node = malloc(sizeof(StackNode));
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
return stack; // allocation failed -> return unchanged stack
|
return stack; // allocation failed -> return unchanged stack
|
||||||
|
|
||||||
node->data = data;
|
node->data = data; // Set the data for the new node
|
||||||
node->next = stack;
|
node->next = stack; // New node points to the previous top of the stack
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-5
@@ -3,7 +3,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "bintree.h"
|
#include "bintree.h"
|
||||||
|
|
||||||
// comparator for unsigned int values stored by value in heap
|
// Vergleichsfunktion für unsigned int
|
||||||
static int cmp_uint_ptr(const void *a, const void *b)
|
static int cmp_uint_ptr(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
unsigned int va = *(const unsigned int *)a;
|
unsigned int va = *(const unsigned int *)a;
|
||||||
@@ -19,7 +19,7 @@ int main(void)
|
|||||||
unsigned int vals[] = {5, 2, 8, 1, 3, 7, 9};
|
unsigned int vals[] = {5, 2, 8, 1, 3, 7, 9};
|
||||||
const size_t n = sizeof(vals)/sizeof(vals[0]);
|
const size_t n = sizeof(vals)/sizeof(vals[0]);
|
||||||
|
|
||||||
// insert values (copy made by addToTree)
|
// Werte in den Baum einfügen
|
||||||
for(size_t i = 0; i < n; i++)
|
for(size_t i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
int isDup = 0;
|
int isDup = 0;
|
||||||
@@ -27,22 +27,25 @@ int main(void)
|
|||||||
if(root == NULL && isDup == 0) { fprintf(stderr, "addToTree allocation failed\n"); return 1; }
|
if(root == NULL && isDup == 0) { fprintf(stderr, "addToTree allocation failed\n"); return 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Baumgröße prüfen
|
||||||
unsigned int sz = treeSize(root);
|
unsigned int sz = treeSize(root);
|
||||||
if(sz != n) { fprintf(stderr, "treeSize expected %zu got %u\n", n, sz); clearTree(root); return 2; }
|
if(sz != n) { fprintf(stderr, "treeSize expected %zu got %u\n", n, sz); clearTree(root); return 2; }
|
||||||
|
|
||||||
// inorder traversal using nextTreeData
|
// Inorder-Traversierung (muss sortiert sein)
|
||||||
unsigned int last = 0;
|
unsigned int last = 0;
|
||||||
int first = 1;
|
int first = 1;
|
||||||
unsigned int *data = nextTreeData(root);
|
unsigned int *data = nextTreeData(root);
|
||||||
while(data != NULL)
|
while(data != NULL)
|
||||||
{
|
{
|
||||||
unsigned int v = *data;
|
unsigned int v = *data;
|
||||||
|
// Prüfen, ob Reihenfolge korrekt ist
|
||||||
if(!first && v < last) { fprintf(stderr, "inorder traversal not sorted: %u after %u\n", v, last); clearTree(root); return 3; }
|
if(!first && v < last) { fprintf(stderr, "inorder traversal not sorted: %u after %u\n", v, last); clearTree(root); return 3; }
|
||||||
last = v; first = 0;
|
last = v; first = 0;
|
||||||
data = nextTreeData(NULL);
|
data = nextTreeData(NULL); // nächstes Element holen
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTree(root);
|
clearTree(root); // Speicher freigeben
|
||||||
printf("test_bintree: OK\n");
|
printf("test_bintree: OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
+69
-19
@@ -1,41 +1,91 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "numbers.h"
|
#include "numbers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selbsttest für createNumbers() und getDuplicate().
|
||||||
|
*
|
||||||
|
* Erzeugt ein Array aus len Zufallszahlen mit genau einem duplizierten Wert,
|
||||||
|
* validiert die Eigenschaften per Zähl-Array (Wertebereich, Häufigkeiten)
|
||||||
|
* und prüft anschließend, ob getDuplicate() dasselbe Duplikat ermittelt.
|
||||||
|
*
|
||||||
|
* Rückgabecodes:
|
||||||
|
* 0: OK
|
||||||
|
* 1: createNumbers() fehlgeschlagen
|
||||||
|
* 2: Speicherfehler für counts
|
||||||
|
* 3: Wert außerhalb des Bereichs [1..2*len]
|
||||||
|
* 4: Ein Wert erscheint öfter als zweimal
|
||||||
|
* 5: Nicht genau ein Duplikat gefunden
|
||||||
|
* 6: getDuplicate() liefert anderes Ergebnis als Zählung
|
||||||
|
*/
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
unsigned int len = 100;
|
unsigned int len = 100; // Anzahl zu erzeugender Zahlen
|
||||||
unsigned int *nums = createNumbers(len);
|
unsigned int *nums = createNumbers(len);
|
||||||
if(nums == NULL) { fprintf(stderr, "createNumbers returned NULL\n"); return 1; }
|
if (nums == NULL) {
|
||||||
|
fprintf(stderr, "createNumbers returned NULL\n");
|
||||||
// count occurrences
|
return 1; // Erzeugung fehlgeschlagen
|
||||||
unsigned int maxVal = 2 * len;
|
|
||||||
unsigned int *counts = calloc(maxVal + 1, sizeof(unsigned int));
|
|
||||||
if(counts == NULL) { free(nums); return 2; }
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if(nums[i] > maxVal) { fprintf(stderr, "value out of expected range\n"); free(nums); free(counts); return 3; }
|
|
||||||
counts[nums[i]]++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int maxVal = 2 * len; // Erlaubter Bereich: [1 .. 2*len]
|
||||||
|
|
||||||
|
// Zähl-Array für Häufigkeiten pro Wert (Index 0 bleibt ungenutzt)
|
||||||
|
unsigned int *counts = calloc(maxVal + 1, sizeof(unsigned int));
|
||||||
|
if (counts == NULL) {
|
||||||
|
free(nums);
|
||||||
|
return 2; // Speicherfehler bei counts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Häufigkeiten bestimmen und gleichzeitig Bereich prüfen
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
unsigned int v = nums[i];
|
||||||
|
if (v == 0 || v > maxVal) { // sollte nicht passieren, wenn createNumbers korrekt ist
|
||||||
|
fprintf(stderr, "value out of expected range\n");
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
counts[v]++; // Auftreten des Werts v zählen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exakt ein Wert muss doppelt vorkommen; keiner darf >2-mal vorkommen
|
||||||
int duplicatesFound = 0;
|
int duplicatesFound = 0;
|
||||||
unsigned int duplicateValue = 0;
|
unsigned int duplicateValue = 0;
|
||||||
for(unsigned int v = 1; v <= maxVal; v++)
|
|
||||||
{
|
for (unsigned int v = 1; v <= maxVal; v++) {
|
||||||
if(counts[v] == 2) { duplicatesFound++; duplicateValue = v; }
|
if (counts[v] == 2) {
|
||||||
else if(counts[v] > 2) { fprintf(stderr, "value %u appears more than twice\n", v); free(nums); free(counts); return 4; }
|
duplicatesFound++;
|
||||||
|
duplicateValue = v; // den doppelten Wert merken
|
||||||
|
} else if (counts[v] > 2) {
|
||||||
|
fprintf(stderr, "value %u appears more than twice\n", v);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 4; // Vertragsbruch: zu häufiges Auftreten
|
||||||
|
}
|
||||||
|
// counts[v] == 0 oder 1 sind unkritisch
|
||||||
}
|
}
|
||||||
|
|
||||||
if(duplicatesFound != 1) { fprintf(stderr, "expected exactly one duplicated value, found %d\n", duplicatesFound); free(nums); free(counts); return 5; }
|
if (duplicatesFound != 1) {
|
||||||
|
fprintf(stderr, "expected exactly one duplicated value, found %d\n", duplicatesFound);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 5; // zu wenige/zu viele Duplikate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ergebnis von getDuplicate() mit der Zählung abgleichen
|
||||||
unsigned int found = getDuplicate(nums, len);
|
unsigned int found = getDuplicate(nums, len);
|
||||||
if(found != duplicateValue) { fprintf(stderr, "getDuplicate returned %u expected %u\n", found, duplicateValue); free(nums); free(counts); return 6; }
|
if (found != duplicateValue) {
|
||||||
|
fprintf(stderr, "getDuplicate returned %u expected %u\n", found, duplicateValue);
|
||||||
|
free(nums);
|
||||||
|
free(counts);
|
||||||
|
return 6; // Abweichung zwischen Methoden
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ressourcen freigeben und Erfolg melden
|
||||||
free(nums);
|
free(nums);
|
||||||
free(counts);
|
free(counts);
|
||||||
|
|
||||||
printf("test_numbers: OK (duplicate = %u)\n", duplicateValue);
|
printf("test_numbers: OK (duplicate = %u)\n", duplicateValue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
BIN
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user