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), * `treeSize`: zählt die Knoten im Baum (rekursiv),
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ * `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 // 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) 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. // 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, // 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. // 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) 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). // Releases all memory resources (including data copies).
// Gibt den gesamten Speicher (Knoten + Daten) frei
void clearTree(TreeNode *root) 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. // Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *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 player_name;39611
lukas;35728 lukas;35728
anton;9956 anton;9956
anton;9944
Anton;9940
player1;3999 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 # 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 # Clean
# -------------------------- # --------------------------

View File

@ -11,10 +11,7 @@
* Duplizieren eines zufälligen Eintrags im Array. * Duplizieren eines zufälligen Eintrags im Array.
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ * 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. //Vergleichsfunktion von qsort
// 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
static int compareUnsignedInt(const void *a, const void *b) static int compareUnsignedInt(const void *a, const void *b)
{ {
const unsigned int *x = (const unsigned int *)a; const unsigned int *x = (const unsigned int *)a;
@ -25,7 +22,7 @@ const unsigned int *x = (const unsigned int *)a;
return 0; return 0;
} }
// Fisher-Yates Shuffle Algorithmus zum Mischen des Arrays //Mischen des Arrays
static void shuffleArray(unsigned int *array, unsigned int n) static void shuffleArray(unsigned int *array, unsigned int n)
{ {
if (n > 1) 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) unsigned int *createNumbers(unsigned int len)
{ {
if (len < 2) return NULL; if (len < 2) return NULL;
// 1. Array reservieren //Dynamisches Array
unsigned int *numbers = malloc(len * sizeof(unsigned int)); unsigned int *numbers = malloc(len * sizeof(unsigned int));
if (numbers == NULL) return NULL; if (numbers == NULL) return NULL;
//Variabelen für den Binärbaum
// Hilfsvariablen für den Baum
TreeNode *root = NULL; TreeNode *root = NULL;
int isDuplicate = 0; int isDuplicate = 0;
unsigned int count = 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) while (count < len - 1)
{ { //Zufallszahlen generieren
// Zufallszahl generieren (1 bis 2*len)
unsigned int value = (rand() % (2 * len)) + 1; 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); root = addToTree(root, &value, sizeof(unsigned int), compareUnsignedInt, &isDuplicate);
// Prüfen: War es ein Duplikat?
if (isDuplicate == 0) if (isDuplicate == 0)
{ { //in array schreiben falls kein Duplikat
// Nein, es war neu! -> Ins Array schreiben
numbers[count] = value; numbers[count] = value;
count++; 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 randomIndex = rand() % (len - 1);
unsigned int duplicateValue = numbers[randomIndex]; unsigned int duplicateValue = numbers[randomIndex];
// Wir schreiben das Duplikat an die allerletzte Stelle
numbers[len - 1] = duplicateValue; 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); root = addToTree(root, &duplicateValue, sizeof(unsigned int), compareUnsignedInt, NULL);
//Array mischen damit duplikat nicht am Ende immer ist
// 4. Mischen
// Da das Duplikat jetzt immer ganz am Ende steht, müssen wir mischen.
shuffleArray(numbers, len); 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); clearTree(root);
return numbers; return numbers;
} }
//get Duplicate
// ... Hierunter bleibt die getDuplicate Funktion deines Kollegen unverändert ...
// Sie ist korrekt implementiert laut Aufgabenstellung (mit qsort)[cite: 11, 43].
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;
} }
//Kopie vom Array anlegen
unsigned int *copy = malloc(len * sizeof(unsigned int)); unsigned int *copy = malloc(len * sizeof(unsigned int));
if (copy == NULL) { if (copy == NULL) {
return 0; return 0;
} }
memcpy(copy, numbers, len * sizeof(unsigned int)); memcpy(copy, numbers, len * sizeof(unsigned int));
qsort(copy, len, sizeof(unsigned int), compareUnsignedInt); qsort(copy, len, sizeof(unsigned int), compareUnsignedInt);
unsigned int duplicate = 0; unsigned int duplicate = 0;
//Duplikat finden
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]) {
duplicate = copy[i]; duplicate = copy[i];
break; break;
} }
} }
//Speicher freigeben
free(copy); free(copy);
return duplicate; return duplicate;
} }

BIN
numbers.o Normal file

Binary file not shown.

31
stack.c
View File

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