Doble-Spiel/numbers.c
Sara 748a39e8c1 cleartree funktion in bintree; getDuplicate in numbers;
Unittests test-Numbers implemented + makefile einbindung
2025-12-04 21:37:05 +01:00

147 lines
5.0 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "numbers.h"
#include "bintree.h"
//TODO: getDuplicate und createNumbers implementieren
/* * * 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. */
// **********************************************
// HILFSFUNKTION FÜR DEN BINÄRBAUM (und später qsort)
// **********************************************
/**
* Vergleicht zwei unsigned int Werte.
* Wird als CompareFctType für den Binärbaum benötigt.
* Rückgabe: < 0 wenn *num1 < *num2, > 0 wenn *num1 > *num2, 0 wenn gleich.
*/
// Implementierung für unsigned int
int compareNumbers(const void *arg1, const void *arg2)
{
// Die void-Pointer auf unsigned int Pointer casten
const unsigned int *num1 = (const unsigned int *)arg1;
const unsigned int *num2 = (const unsigned int *)arg2;
// Werte dereferenzieren und vergleichen
if (*num1 < *num2) return -1;
if (*num1 > *num2) return 1;
return 0;
}
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// creating random numbers.
unsigned int *createNumbers(unsigned int len)
{
srand(time(NULL));
// Sicherheitscheck für len (Minimum 3, siehe main.c)
if (len < 3) return NULL;
// Allokiere Speicher für 'len' unsigned int
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (numbers == NULL)
{
// Speicher konnte nicht reserviert werden
return NULL;
}
// 2. Binären Suchbaum initialisieren
TreeNode *treeRoot = NULL;
// Variablen für Schleife und Zufallszahl
unsigned int randomNumber;
int isDuplicate; // Flag für addToTree
// Die Schleife läuft nur bis len - 1, da die letzte Zahl das Duplikat wird
for (unsigned int i = 0; i < len - 1; i++)
{
do
{
// 3a. Zufallszahl generieren [1, 2 * len]
// Formel: (rand() % (Obergrenze - Untergrenze + 1)) + Untergrenze
randomNumber = (rand() % (2 * len)) + 1;
// 3b. Zahl in den Binärbaum einfügen (und Duplikat prüfen)
// addToTree gibt treeRoot zurück, das wird für die nächste Iteration gespeichert.
// isDuplicate wird auf 1 gesetzt, wenn die Zahl schon existiert.
treeRoot = addToTree(
treeRoot,
&randomNumber,
sizeof(unsigned int),
compareNumbers,
&isDuplicate
);
// Fehlerprüfung: Konnte addToTree Speicher allokieren?
if (treeRoot == NULL) {
// Konnte ersten Knoten nicht erstellen, breche ab und gib Speicher frei
free(numbers);
return NULL;
}
} while (isDuplicate); // Solange eine Duplikat-Nummer generiert wurde, wiederhole.
// 4. Eindeutige Zahl im Array speichern
numbers[i] = randomNumber;
}
// 5. Duplikat erzeugen (letzter Eintrag des Arrays)
// Wähle einen zufälligen Index der bereits gefüllten eindeutigen Zahlen [0, len - 2]
// Wir wählen aus den len-1 bereits gefüllten Einträgen.
unsigned int duplicateIndex = rand() % (len - 1);
// Kopiere den Wert des zufälligen Index auf das letzte Element
numbers[len - 1] = numbers[duplicateIndex];
// 6. Aufräumen: Speicher des Binärbaums freigeben (sehr wichtig!)
// Voraussetzung: clearTree ist in bintree.c implementiert.
clearTree(treeRoot);
return numbers;
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
{
unsigned int duplicate = 0; // Rückgabewert (0 bei Fehler)
// 1. Array-Kopie auf dem Heap erstellen (muss mit free freigegeben werden!)
unsigned int sizeInBytes = len * sizeof(unsigned int);
unsigned int *tempArray = (unsigned int *)malloc(sizeInBytes);
if (tempArray == NULL) {
return 0; // Speicherfehler
}
// Daten kopieren
memcpy(tempArray, numbers, sizeInBytes);
// 2. Sortieren der Kopie mit qsort (siehe Skript 14_effiziente_sortieralgorithmen.pdf)
// qsort hat eine durchschnittliche Komplexität von O(n log n) [cite: 261]
qsort(tempArray, len, sizeof(unsigned int), compareNumbers);
// 3. Duplikat finden durch Vergleich benachbarter Elemente
for (unsigned int i = 0; i < len - 1; i++)
{
// Vergleiche Element i mit Element i+1
if (tempArray[i] == tempArray[i + 1])
{
duplicate = tempArray[i];
break; // Duplikat gefunden, Schleife beenden
}
}
// 4. Speicher freigeben!
free(tempArray);
return duplicate;
}