generated from freudenreichan/info2Praktikum-DobleSpiel
Add Unity unit tests for numbers and finalize sorting
This commit is contained in:
parent
624d75e7cd
commit
1ab79ceb81
154
bintree.c
154
bintree.c
@ -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);
|
||||
}
|
||||
151
exportToHTML/numbers.c.html
Normal file
151
exportToHTML/numbers.c.html
Normal 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"><stdlib.h></span>
|
||||
<span class="s0">#include </span><span class="s2"><stdio.h></span>
|
||||
<span class="s0">#include </span><span class="s2"><time.h></span>
|
||||
<span class="s0">#include </span><span class="s2"><string.h></span>
|
||||
<span class="s0">#include </span><span class="s2">"numbers.h"</span>
|
||||
<span class="s0">#include </span><span class="s2">"bintree.h"</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">< *</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">> *</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">> </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">> </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">< </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 "Türsteher"</span>
|
||||
<span class="s4">while </span><span class="s5">(</span><span class="s1">count </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="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 &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">, &</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">, &</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! -> 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">, &</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">< </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">< </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
BIN
highscore.o
Normal file
Binary file not shown.
@ -2,4 +2,6 @@ anton;39632
|
||||
player_name;39611
|
||||
lukas;35728
|
||||
anton;9956
|
||||
anton;9944
|
||||
Anton;9940
|
||||
player1;3999
|
||||
|
||||
9
makefile
9
makefile
@ -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
|
||||
# --------------------------
|
||||
|
||||
60
numbers.c
60
numbers.c
@ -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;
|
||||
}
|
||||
31
stack.c
31
stack.c
@ -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
23
stack.h
@ -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
test_numbers
BIN
test_numbers
Binary file not shown.
100
test_numbers.c
100
test_numbers.c
@ -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();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user