Add Unity unit tests for numbers and finalize sorting

This commit is contained in:
Anton Timofeev 2025-12-17 14:12:36 +01:00
parent 624d75e7cd
commit 1ab79ceb81
16 changed files with 435 additions and 93 deletions

152
bintree.c
View File

@ -8,29 +8,177 @@
* `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
//Hilfsfunktion für addToTree. Erstellt eine treenode.
static TreeNode* createTreeNode(const void *data, size_t dataSize)
{
TreeNode* newNode = calloc(1, sizeof(TreeNode));
if(!newNode)
{
return NULL;
}
newNode ->data = malloc(dataSize);
if(!newNode->data)
{
free(newNode);
return NULL;
}
memcpy(newNode -> data, data, dataSize);
return newNode;
}
// 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).
// if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). (auf 1 wenn duplikat geaddet)
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
{
if(!root)
{
TreeNode *newNode = createTreeNode(data, dataSize);
if(isDuplicate != NULL)
{
*isDuplicate = 0;
}
return newNode;
}
int compare = compareFct(data, root-> data);
if(compare < 0)
{
root -> left = addToTree(root -> left, data, dataSize, compareFct, isDuplicate);
}
else if(compare > 0)
{
root -> right = addToTree(root -> right, data, dataSize, compareFct, isDuplicate);
}
else
{
if(isDuplicate != NULL)
{
*isDuplicate = 1;
return root;
}
//Konvention: rechts ist >= also das Duplikat wird nach rechts verfrachtet.
root -> right = addToTree(root -> right, data, dataSize, compareFct, isDuplicate);
}
return root;
}
// Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction.
// 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.
// Wir brauchen eine statische Variable, die überdauernd existiert
// (Alternativ kann man diese auch global ausserhalb definieren)
// Die statische Variable (das Gedächtnis) muss außerhalb oder static innerhalb sein
/*
* nextTreeData - Iterative In-Order Traversierung (wie strtok)
* * Funktionsweise:
* 1. Initialisierung (root != NULL):
* - Löscht alten Stack.
* - Wandert von root so weit nach LINKS wie möglich.
* - Pushed alle Knoten auf dem Weg auf den Stack.
* -> Das kleinste Element liegt nun oben.
* * 2. Iteration (root == NULL):
* - Pop: Nimmt oberstes Element vom Stack (aktuell kleinstes).
* - Logik: Hat dieses Element einen RECHTEN Nachbarn?
* -> JA: Gehe eins nach rechts, dann wieder alles nach LINKS pushen.
* -> NEIN: Nichts tun (der Elternknoten liegt schon als nächstes auf dem Stack).
* - Gibt die Daten des gepoppten Elements zurück.
*/
static StackNode *iteratorStack = NULL;
void *nextTreeData(TreeNode *root)
{
//neuer Baum wird übergeben (root != NULL)
if (root != NULL)
{
// 1. Aufräumen: Falls noch Reste vom letzten Mal da sind
if (iteratorStack != NULL) {
clearStack(iteratorStack);
iteratorStack = NULL;
}
// 2. Initial befüllen: "Push root and all left nodes"
TreeNode *currentNode = root;
while (currentNode != NULL)
{
iteratorStack = push(iteratorStack, currentNode);
// Immer weiter nach links absteigen
currentNode = currentNode->left;
}
}
// PHASE 2: Iteration (Nächsten Wert holen)
// Wenn der Stack leer ist (oder leer war), sind wir fertig.
if (iteratorStack == NULL)
{
return NULL;
}
// 1. Wir schauen uns das oberste Element an (der nächste Knoten in der Reihe)
// Wir wissen, dass es ein TreeNode* ist, also casten wir.
TreeNode *nodeToReturn = (TreeNode*) top(iteratorStack);
// 2. Wir entfernen ihn vom Stack (er ist jetzt "verarbeitet")
// Auch hier: pop gibt den neuen Head zurück, also variable aktualisieren!
iteratorStack = pop(iteratorStack);
// 3. Wir retten die Nutzer-Daten (z.B. den Integer), bevor wir weiterwandern
void *userData = nodeToReturn->data;
// 4. Nachfolger suchen (Die Logik für In-Order: Rechts, dann alles links)
if (nodeToReturn->right != NULL)
{
TreeNode *currentNode = nodeToReturn->right;
while (currentNode != NULL)
{
// Auch hier: Stack aktualisieren
iteratorStack = push(iteratorStack, currentNode);
currentNode = currentNode->left;
}
}
// Wir geben die echten Daten zurück (nicht den Knoten, sondern den Inhalt)
return userData;
}
// Releases all memory resources (including data copies).
// Gibt den gesamten Speicher (Knoten + Daten) frei
void clearTree(TreeNode *root)
{
if (root)
{
// 2. Rekursion: Erst tief in den Baum absteigen (Post-Order)
clearTree(root->left);
clearTree(root->right);
// 3. Jetzt sind die Kinder weg. Wir kümmern uns um den aktuellen Knoten.
// Erst den Inhalt (die Datenkopie) löschen!
// (free(NULL) ist in C erlaubt, daher müssen wir nicht zwingend auf NULL prüfen,
// aber es schadet auch nicht).
free(root->data);
// 4. Dann den Container (den Knoten selbst) löschen
free(root);
}
}
// Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root)
{
// Abbruchbedingung: Wenn kein Knoten da ist, ist die Größe 0
if (root == NULL)
{
return 0;
}
// Rekursionsschritt:
// 1 (für den aktuellen Knoten) + alles im linken Baum + alles im rechten Baum
return 1 + treeSize(root->left) + treeSize(root->right);
}

BIN
bintree.o Normal file

Binary file not shown.

BIN
doble Executable file

Binary file not shown.

151
exportToHTML/numbers.c.html Normal file
View File

@ -0,0 +1,151 @@
<html>
<head>
<title>numbers.c</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
.s0 { color: #b3ae60;}
.s1 { color: #bcbec4;}
.s2 { color: #6aab73;}
.s3 { color: #7a7e85;}
.s4 { color: #cf8e6d;}
.s5 { color: #bcbec4;}
.s6 { color: #2aacb8;}
</style>
</head>
<body bgcolor="#1e1f22">
<table CELLSPACING=0 CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#606060" >
<tr><td><center>
<font face="Arial, Helvetica" color="#000000">
numbers.c</font>
</center></td></tr></table>
<pre><span class="s0">#include </span><span class="s2">&lt;stdlib.h&gt;</span>
<span class="s0">#include </span><span class="s2">&lt;stdio.h&gt;</span>
<span class="s0">#include </span><span class="s2">&lt;time.h&gt;</span>
<span class="s0">#include </span><span class="s2">&lt;string.h&gt;</span>
<span class="s0">#include </span><span class="s2">&quot;numbers.h&quot;</span>
<span class="s0">#include </span><span class="s2">&quot;bintree.h&quot;</span>
<span class="s3">//TODO: getDuplicate und createNumbers implementieren</span>
<span class="s3">/* * * 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. */</span>
<span class="s3">// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.</span>
<span class="s3">// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while</span>
<span class="s3">// creating random numbers.</span>
<span class="s3">// Vergleichsfunktion für qsort</span>
<span class="s4">static int </span><span class="s1">compareUnsignedInt</span><span class="s5">(</span><span class="s4">const void </span><span class="s5">*</span><span class="s1">a</span><span class="s5">, </span><span class="s4">const void </span><span class="s5">*</span><span class="s1">b</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s4">const unsigned int </span><span class="s5">*</span><span class="s1">x </span><span class="s5">= (</span><span class="s4">const unsigned int </span><span class="s5">*)</span><span class="s1">a</span><span class="s5">;</span>
<span class="s4">const unsigned int </span><span class="s5">*</span><span class="s1">y </span><span class="s5">= (</span><span class="s4">const unsigned int </span><span class="s5">*)</span><span class="s1">b</span><span class="s5">;</span>
<span class="s4">if </span><span class="s5">(*</span><span class="s1">x </span><span class="s5">&lt; *</span><span class="s1">y</span><span class="s5">) </span><span class="s4">return </span><span class="s5">-</span><span class="s6">1</span><span class="s5">;</span>
<span class="s4">if </span><span class="s5">(*</span><span class="s1">x </span><span class="s5">&gt; *</span><span class="s1">y</span><span class="s5">) </span><span class="s4">return </span><span class="s6">1</span><span class="s5">;</span>
<span class="s4">return </span><span class="s6">0</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s3">// Fisher-Yates Shuffle Algorithmus zum Mischen des Arrays</span>
<span class="s4">static void </span><span class="s1">shuffleArray</span><span class="s5">(</span><span class="s4">unsigned int </span><span class="s5">*</span><span class="s1">array</span><span class="s5">, </span><span class="s4">unsigned int </span><span class="s1">n</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">n </span><span class="s5">&gt; </span><span class="s6">1</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s4">for </span><span class="s5">(</span><span class="s4">unsigned int </span><span class="s1">i </span><span class="s5">= </span><span class="s1">n </span><span class="s5">- </span><span class="s6">1</span><span class="s5">; </span><span class="s1">i </span><span class="s5">&gt; </span><span class="s6">0</span><span class="s5">; </span><span class="s1">i</span><span class="s5">--)</span>
<span class="s5">{</span>
<span class="s4">unsigned int </span><span class="s1">j </span><span class="s5">= </span><span class="s1">rand</span><span class="s5">() % (</span><span class="s1">i </span><span class="s5">+ </span><span class="s6">1</span><span class="s5">);</span>
<span class="s4">unsigned int </span><span class="s1">temp </span><span class="s5">= </span><span class="s1">array</span><span class="s5">[</span><span class="s1">i</span><span class="s5">];</span>
<span class="s1">array</span><span class="s5">[</span><span class="s1">i</span><span class="s5">] = </span><span class="s1">array</span><span class="s5">[</span><span class="s1">j</span><span class="s5">];</span>
<span class="s1">array</span><span class="s5">[</span><span class="s1">j</span><span class="s5">] = </span><span class="s1">temp</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s5">}</span>
<span class="s5">}</span>
<span class="s4">unsigned int </span><span class="s5">*</span><span class="s1">createNumbers</span><span class="s5">(</span><span class="s4">unsigned int </span><span class="s1">len</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">len </span><span class="s5">&lt; </span><span class="s6">2</span><span class="s5">) </span><span class="s4">return </span><span class="s1">NULL</span><span class="s5">;</span>
<span class="s3">// 1. Array reservieren</span>
<span class="s4">unsigned int </span><span class="s5">*</span><span class="s1">numbers </span><span class="s5">= </span><span class="s1">malloc</span><span class="s5">(</span><span class="s1">len </span><span class="s5">* </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">));</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">numbers </span><span class="s5">== </span><span class="s1">NULL</span><span class="s5">) </span><span class="s4">return </span><span class="s1">NULL</span><span class="s5">;</span>
<span class="s3">// Hilfsvariablen für den Baum</span>
<span class="s1">TreeNode </span><span class="s5">*</span><span class="s1">root </span><span class="s5">= </span><span class="s1">NULL</span><span class="s5">;</span>
<span class="s4">int </span><span class="s1">isDuplicate </span><span class="s5">= </span><span class="s6">0</span><span class="s5">;</span>
<span class="s4">unsigned int </span><span class="s1">count </span><span class="s5">= </span><span class="s6">0</span><span class="s5">;</span>
<span class="s3">// 2. PHASE 1: Erzeuge (len - 1) EINZIGARTIGE Zahlen mit Hilfe des Baums</span>
<span class="s3">// Wir nutzen den Baum als &quot;Türsteher&quot;</span>
<span class="s4">while </span><span class="s5">(</span><span class="s1">count </span><span class="s5">&lt; </span><span class="s1">len </span><span class="s5">- </span><span class="s6">1</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s3">// Zufallszahl generieren (1 bis 2*len)</span>
<span class="s4">unsigned int </span><span class="s1">value </span><span class="s5">= (</span><span class="s1">rand</span><span class="s5">() % (</span><span class="s6">2 </span><span class="s5">* </span><span class="s1">len</span><span class="s5">)) + </span><span class="s6">1</span><span class="s5">;</span>
<span class="s3">// Versuchen, in den Baum einzufügen</span>
<span class="s3">// Wir übergeben &amp;isDuplicate, damit der Baum Duplikate ABLEHNT.</span>
<span class="s1">root </span><span class="s5">= </span><span class="s1">addToTree</span><span class="s5">(</span><span class="s1">root</span><span class="s5">, &amp;</span><span class="s1">value</span><span class="s5">, </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">), </span><span class="s1">compareUnsignedInt</span><span class="s5">, &amp;</span><span class="s1">isDuplicate</span><span class="s5">);</span>
<span class="s3">// Prüfen: War es ein Duplikat?</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">isDuplicate </span><span class="s5">== </span><span class="s6">0</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s3">// Nein, es war neu! -&gt; Ins Array schreiben</span>
<span class="s1">numbers</span><span class="s5">[</span><span class="s1">count</span><span class="s5">] = </span><span class="s1">value</span><span class="s5">;</span>
<span class="s1">count</span><span class="s5">++;</span>
<span class="s5">}</span>
<span class="s3">// Falls isDuplicate == 1, machen wir einfach weiter (while-Schleife läuft weiter)</span>
<span class="s5">}</span>
<span class="s3">// 3. PHASE 2: Das garantierte Duplikat erzeugen</span>
<span class="s3">// Wir wählen zufällig eine der bereits existierenden Zahlen aus</span>
<span class="s4">unsigned int </span><span class="s1">randomIndex </span><span class="s5">= </span><span class="s1">rand</span><span class="s5">() % (</span><span class="s1">len </span><span class="s5">- </span><span class="s6">1</span><span class="s5">);</span>
<span class="s4">unsigned int </span><span class="s1">duplicateValue </span><span class="s5">= </span><span class="s1">numbers</span><span class="s5">[</span><span class="s1">randomIndex</span><span class="s5">];</span>
<span class="s3">// Wir schreiben das Duplikat an die allerletzte Stelle</span>
<span class="s1">numbers</span><span class="s5">[</span><span class="s1">len </span><span class="s5">- </span><span class="s6">1</span><span class="s5">] = </span><span class="s1">duplicateValue</span><span class="s5">;</span>
<span class="s3">// Optional: Duplikat auch in den Baum einfügen (Modus: Akzeptieren / isDuplicate = NULL)</span>
<span class="s3">// Damit der Baum konsistent zum Array ist (falls man ihn später noch braucht).</span>
<span class="s1">root </span><span class="s5">= </span><span class="s1">addToTree</span><span class="s5">(</span><span class="s1">root</span><span class="s5">, &amp;</span><span class="s1">duplicateValue</span><span class="s5">, </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">), </span><span class="s1">compareUnsignedInt</span><span class="s5">, </span><span class="s1">NULL</span><span class="s5">);</span>
<span class="s3">// 4. Mischen</span>
<span class="s3">// Da das Duplikat jetzt immer ganz am Ende steht, müssen wir mischen.</span>
<span class="s1">shuffleArray</span><span class="s5">(</span><span class="s1">numbers</span><span class="s5">, </span><span class="s1">len</span><span class="s5">);</span>
<span class="s3">// 5. Aufräumen</span>
<span class="s3">// Der Baum war nur ein Hilfsmittel zur Überprüfung. Er wird jetzt gelöscht.</span>
<span class="s3">// WICHTIG: Damit verhindern wir Memory Leaks [cite: 12]</span>
<span class="s1">clearTree</span><span class="s5">(</span><span class="s1">root</span><span class="s5">);</span>
<span class="s4">return </span><span class="s1">numbers</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s3">// ... Hierunter bleibt die getDuplicate Funktion deines Kollegen unverändert ...</span>
<span class="s3">// Sie ist korrekt implementiert laut Aufgabenstellung (mit qsort)[cite: 11, 43].</span>
<span class="s4">unsigned int </span><span class="s1">getDuplicate</span><span class="s5">(</span><span class="s4">const unsigned int </span><span class="s1">numbers</span><span class="s5">[], </span><span class="s4">unsigned int </span><span class="s1">len</span><span class="s5">)</span>
<span class="s5">{</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">numbers </span><span class="s5">== </span><span class="s1">NULL </span><span class="s5">|| </span><span class="s1">len </span><span class="s5">&lt; </span><span class="s6">2</span><span class="s5">) {</span>
<span class="s4">return </span><span class="s6">0</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s4">unsigned int </span><span class="s5">*</span><span class="s1">copy </span><span class="s5">= </span><span class="s1">malloc</span><span class="s5">(</span><span class="s1">len </span><span class="s5">* </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">));</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">copy </span><span class="s5">== </span><span class="s1">NULL</span><span class="s5">) {</span>
<span class="s4">return </span><span class="s6">0</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s1">memcpy</span><span class="s5">(</span><span class="s1">copy</span><span class="s5">, </span><span class="s1">numbers</span><span class="s5">, </span><span class="s1">len </span><span class="s5">* </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">));</span>
<span class="s1">qsort</span><span class="s5">(</span><span class="s1">copy</span><span class="s5">, </span><span class="s1">len</span><span class="s5">, </span><span class="s4">sizeof</span><span class="s5">(</span><span class="s4">unsigned int</span><span class="s5">), </span><span class="s1">compareUnsignedInt</span><span class="s5">);</span>
<span class="s4">unsigned int </span><span class="s1">duplicate </span><span class="s5">= </span><span class="s6">0</span><span class="s5">;</span>
<span class="s4">for </span><span class="s5">(</span><span class="s4">unsigned int </span><span class="s1">i </span><span class="s5">= </span><span class="s6">0</span><span class="s5">; </span><span class="s1">i </span><span class="s5">+ </span><span class="s6">1 </span><span class="s5">&lt; </span><span class="s1">len</span><span class="s5">; ++</span><span class="s1">i</span><span class="s5">) {</span>
<span class="s4">if </span><span class="s5">(</span><span class="s1">copy</span><span class="s5">[</span><span class="s1">i</span><span class="s5">] == </span><span class="s1">copy</span><span class="s5">[</span><span class="s1">i </span><span class="s5">+ </span><span class="s6">1</span><span class="s5">]) {</span>
<span class="s1">duplicate </span><span class="s5">= </span><span class="s1">copy</span><span class="s5">[</span><span class="s1">i</span><span class="s5">];</span>
<span class="s4">break</span><span class="s5">;</span>
<span class="s5">}</span>
<span class="s5">}</span>
<span class="s1">free</span><span class="s5">(</span><span class="s1">copy</span><span class="s5">);</span>
<span class="s4">return </span><span class="s1">duplicate</span><span class="s5">;</span>
<span class="s5">}</span></pre>
</body>
</html>

BIN
highscore.o Normal file

Binary file not shown.

View File

@ -2,4 +2,6 @@ anton;39632
player_name;39611
lukas;35728
anton;9956
anton;9944
Anton;9940
player1;3999

BIN
main.o Normal file

Binary file not shown.

View File

@ -35,9 +35,14 @@ $(program_obj_filesobj_files): %.o: %.c
# --------------------------
# Unit Tests
# --------------------------
unitTests:
echo "needs to be implemented"
unitTests: test_numbers
./test_numbers
test_numbers: test_numbers.c numbers.c bintree.c stack.c unity/unity.c
gcc -Wall -Wextra -std=c99 -Iunity \
-o test_numbers \
test_numbers.c numbers.c bintree.c stack.c unity/unity.c
# --------------------------
# Clean
# --------------------------

View File

@ -11,10 +11,7 @@
* 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.
// Vergleichsfunktion für qsort
//Vergleichsfunktion von qsort
static int compareUnsignedInt(const void *a, const void *b)
{
const unsigned int *x = (const unsigned int *)a;
@ -25,7 +22,7 @@ const unsigned int *x = (const unsigned int *)a;
return 0;
}
// Fisher-Yates Shuffle Algorithmus zum Mischen des Arrays
//Mischen des Arrays
static void shuffleArray(unsigned int *array, unsigned int n)
{
if (n > 1)
@ -39,91 +36,68 @@ static void shuffleArray(unsigned int *array, unsigned int n)
}
}
}
//Wenn weniger als zwei Zahlen
unsigned int *createNumbers(unsigned int len)
{
if (len < 2) return NULL;
// 1. Array reservieren
//Dynamisches Array
unsigned int *numbers = malloc(len * sizeof(unsigned int));
if (numbers == NULL) return NULL;
// Hilfsvariablen für den Baum
//Variabelen für den Binärbaum
TreeNode *root = NULL;
int isDuplicate = 0;
unsigned int count = 0;
// 2. PHASE 1: Erzeuge (len - 1) EINZIGARTIGE Zahlen mit Hilfe des Baums
// Wir nutzen den Baum als "Türsteher"
while (count < len - 1)
{
// Zufallszahl generieren (1 bis 2*len)
{ //Zufallszahlen generieren
unsigned int value = (rand() % (2 * len)) + 1;
// Versuchen, in den Baum einzufügen
// Wir übergeben &isDuplicate, damit der Baum Duplikate ABLEHNT.
root = addToTree(root, &value, sizeof(unsigned int), compareUnsignedInt, &isDuplicate);
// Prüfen: War es ein Duplikat?
if (isDuplicate == 0)
{
// Nein, es war neu! -> Ins Array schreiben
{ //in array schreiben falls kein Duplikat
numbers[count] = value;
count++;
}
// Falls isDuplicate == 1, machen wir einfach weiter (while-Schleife läuft weiter)
}
// 3. PHASE 2: Das garantierte Duplikat erzeugen
// Wir wählen zufällig eine der bereits existierenden Zahlen aus
}
//Duplikat erzeugen
unsigned int randomIndex = rand() % (len - 1);
unsigned int duplicateValue = numbers[randomIndex];
// Wir schreiben das Duplikat an die allerletzte Stelle
numbers[len - 1] = duplicateValue;
// Optional: Duplikat auch in den Baum einfügen (Modus: Akzeptieren / isDuplicate = NULL)
// Damit der Baum konsistent zum Array ist (falls man ihn später noch braucht).
root = addToTree(root, &duplicateValue, sizeof(unsigned int), compareUnsignedInt, NULL);
// 4. Mischen
// Da das Duplikat jetzt immer ganz am Ende steht, müssen wir mischen.
//Array mischen damit duplikat nicht am Ende immer ist
shuffleArray(numbers, len);
// 5. Aufräumen
// Der Baum war nur ein Hilfsmittel zur Überprüfung. Er wird jetzt gelöscht.
// WICHTIG: Damit verhindern wir Memory Leaks [cite: 12]
clearTree(root);
return numbers;
}
// ... Hierunter bleibt die getDuplicate Funktion deines Kollegen unverändert ...
// Sie ist korrekt implementiert laut Aufgabenstellung (mit qsort)[cite: 11, 43].
//get Duplicate
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
if (numbers == NULL || len < 2) {
return 0;
}
//Kopie vom Array anlegen
unsigned int *copy = malloc(len * sizeof(unsigned int));
if (copy == NULL) {
return 0;
}
memcpy(copy, numbers, len * sizeof(unsigned int));
qsort(copy, len, sizeof(unsigned int), compareUnsignedInt);
unsigned int duplicate = 0;
//Duplikat finden
for (unsigned int i = 0; i + 1 < len; ++i) {
if (copy[i] == copy[i + 1]) {
duplicate = copy[i];
break;
}
}
//Speicher freigeben
free(copy);
return duplicate;
}

BIN
numbers.o Normal file

Binary file not shown.

31
stack.c
View File

@ -1,33 +1,34 @@
#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)
{
StackNode *node = malloc(sizeof(StackNode));
if (node == NULL) return stack;
node->data = data;
node->next = stack;
return node;
}
// 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;
StackNode *next = stack->next;
free(stack);
return next;
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
if (stack == NULL) return NULL;
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
while (stack != NULL) {
StackNode *next = stack->next;
free(stack);
stack = next;
}
}

23
stack.h
View File

@ -1,25 +1,22 @@
#ifndef STACK_H
#define STACK_H
/* A stack is a special type of queue which uses the LIFO (last in, first out) principle.
This means that with each new element all other elements are pushed deeper into the stack.
The latest element is taken from the stack. */
// Eigener Stack-Knotentyp, damit es keinen Konflikt mit bintree.h gibt
typedef struct stack_node {
void *data; // Nutzdaten
struct stack_node *next; // Zeiger auf das nächste Element im Stack
} StackNode;
#include <stdlib.h>
//TODO: passenden Datentyp als struct anlegen
// Pushes data as pointer onto the stack.
// Legt ein Element oben auf den 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.)
// Entfernt das oberste Element und gibt den neuen Stack-Kopf zurück
StackNode *pop(StackNode *stack);
// Returns the data of the top element.
// Liefert die Daten des obersten Elements (ohne zu entfernen)
void *top(StackNode *stack);
// Clears stack and releases all memory.
// Gibt den gesamten Stack frei
void clearStack(StackNode *stack);
#endif
#endif // STACK_H

BIN
stack.o Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,30 +1,94 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "unity.h"
#include "numbers.h"
int main(void)
void setUp(void)
{
srand((unsigned int) time(NULL)); // für echte Zufallszahlen
}
void tearDown(void)
{
}
static unsigned int countOccurrences(const unsigned int *numbers,
unsigned int len,
unsigned int value)
{
unsigned int count = 0;
for (unsigned int i = 0; i < len; ++i) {
if (numbers[i] == value) {
count++;
}
}
return count;
}
void test_createNumbers_returns_non_null(void)
{
unsigned int len = 20;
unsigned int *numbers = createNumbers(len);
if (numbers == NULL) {
printf("Fehler: createNumbers returned NULL\n");
return 1;
}
printf("Erzeugtes Array:\n");
for (unsigned int i = 0; i < len; i++) {
printf("%u ", numbers[i]);
}
printf("\n");
unsigned int d = getDuplicate(numbers, len);
printf("Gefundenes Duplikat: %u\n", d);
TEST_ASSERT_NOT_NULL(numbers);
free(numbers);
return 0;
}
void test_createNumbers_value_range(void)
{
unsigned int len = 30;
unsigned int *numbers = createNumbers(len);
TEST_ASSERT_NOT_NULL(numbers);
for (unsigned int i = 0; i < len; ++i) {
TEST_ASSERT_TRUE(numbers[i] >= 1);
TEST_ASSERT_TRUE(numbers[i] <= 2 * len);
}
free(numbers);
}
void test_getDuplicate_finds_exactly_one_duplicate(void)
{
unsigned int len = 25;
unsigned int *numbers = createNumbers(len);
TEST_ASSERT_NOT_NULL(numbers);
unsigned int duplicate = getDuplicate(numbers, len);
TEST_ASSERT_NOT_EQUAL_UINT(0, duplicate);
unsigned int occurrences =
countOccurrences(numbers, len, duplicate);
TEST_ASSERT_EQUAL_UINT(2, occurrences);
free(numbers);
}
void test_error_cases(void)
{
TEST_ASSERT_NULL(createNumbers(0));
TEST_ASSERT_NULL(createNumbers(1));
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(NULL, 10));
unsigned int oneElement[1] = { 42 };
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(oneElement, 1));
}
int main(void)
{
srand((unsigned int) time(NULL));
UNITY_BEGIN();
RUN_TEST(test_createNumbers_returns_non_null);
RUN_TEST(test_createNumbers_value_range);
RUN_TEST(test_getDuplicate_finds_exactly_one_duplicate);
RUN_TEST(test_error_cases);
return UNITY_END();
}

BIN
timer.o Normal file

Binary file not shown.