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