#include #include #include #include #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; }