generated from freudenreichan/info2Praktikum-DobleSpiel
Makefile angepasst, aber mein Clion spackt gerade, weshalb ich es nicht ausführen kann.
167 lines
5.9 KiB
C
167 lines
5.9 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include "numbers.h"
|
|
#include "bintree.h"
|
|
|
|
// --- Vergleichsfunktionen ---
|
|
|
|
// 1. Vergleichsfunktion für qsort (vergleicht unsigned int-Werte)
|
|
int compare_unsigned_int(const void *a, const void *b) {
|
|
unsigned int arg1 = *(const unsigned int*)a;
|
|
unsigned int arg2 = *(const unsigned int*)b;
|
|
|
|
if (arg1 < arg2) return -1;
|
|
if (arg1 > arg2) return 1;
|
|
return 0;
|
|
}
|
|
|
|
// 2. Vergleichsfunktion für den Binärbaum (vergleicht die *Daten* der Knoten)
|
|
// Die Argumente sind Pointer auf die *Daten* (void*), d.h. Pointer auf unsigned int.
|
|
int compare_tree_data(const void *arg1, const void *arg2) {
|
|
// Cast der void*-Pointer auf unsigned int*-Pointer
|
|
unsigned int val1 = *(const unsigned int*)arg1;
|
|
unsigned int val2 = *(const unsigned int*)arg2;
|
|
|
|
if (val1 < val2) return -1;
|
|
if (val1 > val2) return 1;
|
|
return 0;
|
|
}
|
|
|
|
//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. */
|
|
|
|
// 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.
|
|
/* * Erzeugt ein Array mit (len - 1) eindeutigen Zufallszahlen und einem Duplikat.
|
|
* Die Duplikatprüfung erfolgt über den Binärbaum (addToTree).
|
|
*/
|
|
unsigned int *createNumbers(unsigned int len) {
|
|
if (len == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
// 1. Initialisierung
|
|
// Der BST wird zunächst als NULL initialisiert, da addToTree rekursiv arbeitet.
|
|
TreeNode *root = NULL;
|
|
|
|
// 2. Speicher für das Ziel-Array allokieren
|
|
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
|
|
if (numbers == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
unsigned int count = 0;
|
|
unsigned int max_val = 2 * len;
|
|
|
|
// Speichert den Wert, der später dupliziert wird (aus dem Array gewählt)
|
|
unsigned int value_to_duplicate = 0;
|
|
|
|
// 3. Erzeugen von len - 1 eindeutigen Zufallszahlen
|
|
while (count < len - 1) {
|
|
unsigned int random_num = (rand() % max_val) + 1;
|
|
int is_duplicate = 0;
|
|
|
|
// Wir müssen die Zahl als dynamisch allokierten Speicher übergeben,
|
|
// da addToTree eine Kopie davon erwartet.
|
|
unsigned int *num_ptr = (unsigned int *)malloc(sizeof(unsigned int));
|
|
if (num_ptr == NULL) {
|
|
// cleanup: Baum und bereits allokiertes Array freigeben
|
|
clearTree(root);
|
|
free(numbers);
|
|
return NULL;
|
|
}
|
|
*num_ptr = random_num;
|
|
|
|
// Fügen in den Baum ein:
|
|
// root MUSS das Ergebnis der rekursiven addToTree-Funktion speichern!
|
|
root = addToTree(root, num_ptr, sizeof(unsigned int), compare_tree_data, &is_duplicate);
|
|
|
|
if (root == NULL) {
|
|
// Schwerwiegender Fehler bei der Speicherallokation innerhalb von addToTree
|
|
clearTree(root);
|
|
free(numbers);
|
|
free(num_ptr); // Datenpointer freigeben, falls Fehler vor der Kopie auftrat
|
|
return NULL;
|
|
}
|
|
|
|
if (is_duplicate == 0) {
|
|
// Erfolg: Zahl war neu und wurde eingefügt (die Datenkopie liegt nun im Baum)
|
|
numbers[count] = random_num;
|
|
count++;
|
|
|
|
// value_to_duplicate merken
|
|
value_to_duplicate = random_num;
|
|
|
|
// Den lokalen num_ptr NICHT freigeben, da seine Kopie im Baum verwaltet wird.
|
|
} else {
|
|
// Fehler: Duplikat, wurde NICHT eingefügt.
|
|
// Den lokal allokierten Pointer MÜSSEN wir freigeben, da er nicht in den Baum ging.
|
|
free(num_ptr);
|
|
}
|
|
}
|
|
|
|
// 4. Duplizieren eines Eintrags
|
|
// Der duplizierte Wert wird an die letzte Stelle gesetzt.
|
|
if (len > 1) {
|
|
// Wir verwenden value_to_duplicate, um sicherzustellen, dass die Zahl aus dem Array stammt.
|
|
// Wenn len sehr groß ist, wird einfach eine zufällige Zahl aus dem gefüllten Bereich gewählt.
|
|
if (value_to_duplicate == 0) {
|
|
value_to_duplicate = numbers[rand() % (len - 1)];
|
|
}
|
|
numbers[len - 1] = value_to_duplicate;
|
|
}
|
|
|
|
|
|
// 5. Speicher des Baumes freigeben
|
|
// clearTree gibt alle Knoten und die darin enthaltenen Datenkopien frei.
|
|
clearTree(root);
|
|
|
|
// 6. Mischen (Shuffling) des Arrays, um die Ordnung zu randomisieren
|
|
for (unsigned int i = len - 1; i > 0; i--) {
|
|
unsigned int j = rand() % (i + 1);
|
|
unsigned int temp = numbers[i];
|
|
numbers[i] = numbers[j];
|
|
numbers[j] = temp;
|
|
}
|
|
|
|
return numbers;
|
|
}
|
|
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
|
/* * Sortiert das Array und erkennt das Duplikat durch Vergleich benachbarter Elemente.
|
|
* (O(N log N) wegen qsort)
|
|
*/
|
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) {
|
|
if (len < 2) {
|
|
return 0; // Fehler
|
|
}
|
|
|
|
// 1. Array duplizieren, da das Original const ist und sortiert werden muss
|
|
unsigned int *sorted_numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
|
|
if (sorted_numbers == NULL) {
|
|
return 0;
|
|
}
|
|
memcpy(sorted_numbers, numbers, len * sizeof(unsigned int));
|
|
|
|
// 2. Sortieren des Arrays
|
|
qsort(sorted_numbers, len, sizeof(unsigned int), compare_unsigned_int);
|
|
|
|
// 3. Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente
|
|
unsigned int duplicate = 0;
|
|
for (unsigned int i = 0; i < len - 1; i++) {
|
|
if (sorted_numbers[i] == sorted_numbers[i+1]) {
|
|
duplicate = sorted_numbers[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(sorted_numbers);
|
|
|
|
// 4. Ergebnis zurückgeben
|
|
return duplicate;
|
|
} |