generated from freudenreichan/info2Praktikum-DobleSpiel
147 lines
5.0 KiB
C
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;
|
|
} |