generated from freudenreichan/info2Praktikum-DobleSpiel
Add Unity unit tests for numbers and finalize sorting
This commit is contained in:
parent
624d75e7cd
commit
1ab79ceb81
152
bintree.c
152
bintree.c
@ -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);
|
||||||
}
|
}
|
||||||
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
|
player_name;39611
|
||||||
lukas;35728
|
lukas;35728
|
||||||
anton;9956
|
anton;9956
|
||||||
|
anton;9944
|
||||||
|
Anton;9940
|
||||||
player1;3999
|
player1;3999
|
||||||
|
|||||||
9
makefile
9
makefile
@ -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
|
||||||
# --------------------------
|
# --------------------------
|
||||||
|
|||||||
60
numbers.c
60
numbers.c
@ -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;
|
||||||
}
|
}
|
||||||
31
stack.c
31
stack.c
@ -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
23
stack.h
@ -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
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 <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();
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user