diff --git a/numbers_test2.c b/numbers_test2.c deleted file mode 100644 index 0ca098c..0000000 --- a/numbers_test2.c +++ /dev/null @@ -1,199 +0,0 @@ - -#include -#include -#include -#include -#include "numbers.h" -#include "bintree.h" - -/** - * @brief Vergleichsfunktion für unsigned int-Werte zur Verwendung im Binärbaum. - * - * Diese Funktion wird von der Binärbaum-Implementierung genutzt, um die - * Ordnung der Knoten zu bestimmen. Sie vergleicht die dereferenzierten - * unsigned int-Werte a und b. - * - * @param a Pointer auf einen unsigned int-Wert (linker Operand) - * @param b Pointer auf einen unsigned int-Wert (rechter Operand) - * @return -1, falls *a < *b; 1, falls *a > *b; 0, falls *a == *b - */ - - - -/* -Fkt für Binärbaum Implementierung, um Ordnung der Knoten zu bestimmen -Entscheidet, ob links (kleiner) oder rechts (größer) einzufügen ist. -Ergibt der Vergleich = 0, wird das Duplikat erkannt -Geeignet für qsort() und für addToTree() (CompareFctType) -*/ -static int compareUInt(const void *a, const void *b) -{ - unsigned int va = *(const unsigned int *)a; - unsigned int vb = *(const unsigned int *)b; - if (va < vb) return -1; // links - if (va > vb) return 1; // rechts - return 0; -} - -/** - * @brief Erzeugt ein Array aus len Zufallszahlen im Bereich [1 .. 2*len], - * das genau einen duplizierten Wert enthält (d. h. len-1 eindeutige + 1 Duplikat), - * und mischt die Reihenfolge zufällig. - * - * Funktionsweise: - * - Es werden zunächst len-1 eindeutige Zufallszahlen erzeugt. Die Eindeutigkeit wird - * mithilfe eines Binärsuchbaums (BST) geprüft: addToTree() fügt die Zahl ein - * und signalisiert per isDup, ob sie bereits vorhanden war. - * - Anschließend wird eine der bereits erzeugten Zahlen zufällig ausgewählt und - * noch einmal an das Ende des Arrays geschrieben, um das geforderte Duplikat sicherzustellen. - * - Zum Schluss wird das gesamte Array mittels Fisher–Yates-Algorithmus gemischt. - - - - * Fehlerbehandlung: - * - Bei len < 2 wird NULL zurückgegeben, da das Problem ein Duplikat erfordert. - * - Bei Speicher- oder Baum-Insertionsfehlern wird aufgeräumt und NULL zurückgegeben. - * Wichtig: Der Baumzeiger root wird erst nach erfolgreichem Insert aktualisiert, - * um im Fehlerfall kein bereits aufgebautes Teilbaum-Objekt zu verlieren. - - - * Randbedingungen / Annahmen: - * - addToTree(root, &val, sizeof(val), compareUInt, &isDup) setzt isDup: - * isDup == 1 bedeutet „Duplikat gefunden, Baum unverändert“, - * isDup == 0 bedeutet „neuer Wert eingefügt (oder Fehler)“. - * - Bei Speicherfehler gibt addToTree NULL zurück und isDup bleibt 0. - * - clearTree(root) darf mit NULL-Argument aufgerufen werden (No-Op). - * - * Komplexität: - * - Durchschnittlich O(len * log(len)) für die len-1 Einfügungen in den BST. - * - Shuffle in O(len). - * - * @param len Anzahl der zu erzeugenden Werte (muss >= 2 sein) - * @return Pointer auf ein Array mit len Einträgen bei Erfolg; NULL bei Fehlern - */ - - -unsigned int *createNumbers(unsigned int len) -{ - if (len < 2) - return NULL; - - unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len); - if (numbers == NULL) - return NULL; - - - // Zufallszahlengenerator nur einmal pro Prozess initialisieren. - // Hintergrund: Wird createNumbers mehrfach schnell hintereinander gerufen, - // kann time(NULL) identische Seeds liefern und damit identische Zahlenfolgen erzeugen. - - - static int seeded = 0; - if (!seeded) { - srand((unsigned int)time(NULL)); - seeded = 1; - } - - TreeNode *root = NULL; - unsigned int range = 2 * len; - - // Schritt 1: len-1 eindeutige Zufallszahlen erzeugen - for (unsigned int i = 0; i < len - 1; i++) - { - unsigned int val; - int isDup; - - // Wiederholen, bis eine wirklich neue Zahl eingefügt wurde - for (;;) - { - isDup = 0; // vor jedem Insert zurücksetzen, um „alte“ Werte zu vermeiden - val = (unsigned int)(rand() % range) + 1; // Wertebereich [1 .. 2*len] - - // addToTree kann bei Erfolg einen (ggf. neuen) Wurzelzeiger liefern. - // Zur Vermeidung eines Speicherlecks bei Fehlern zunächst in temp speichern. - TreeNode *newRoot = addToTree(root, &val, sizeof(val), compareUInt, &isDup); - - if (newRoot == NULL && isDup == 0) { - // Vermutlich Speicher-/Insertionsfehler: aufräumen und abbrechen - free(numbers); - clearTree(root); // root zeigt noch auf den gültigen Teilbaum - return NULL; - } - - if (!isDup) { - // Einfügen war erfolgreich und der Wert ist eindeutig. - root = newRoot; - numbers[i] = val; - break; - } - // Andernfalls Duplikat: Neue Zufallszahl versuchen. - } - } - - // Schritt 2: Eine der bestehenden Zahlen zufällig duplizieren - unsigned int idx = (unsigned int)(rand() % (len - 1)); // Index im Bereich [0 .. len-2] - numbers[len - 1] = numbers[idx]; - - // Schritt 3: Fisher–Yates-Shuffle über das gesamte Array - for (unsigned int i = len - 1; i > 0; i--) - { - unsigned int j = (unsigned int)(rand() % (i + 1)); - unsigned int tmp = numbers[i]; - numbers[i] = numbers[j]; - numbers[j] = tmp; - } - - // Aufräumen: Baum freigeben - clearTree(root); - return numbers; -} - -/** - * @brief Findet den einzigen duplizierten Wert in einem Array aus len unsigned int. - * - * Funktionsweise: - * - Es wird eine Kopie des Eingabearrays erstellt, um die Reihenfolge des - * Originalarrays nicht zu verändern. - * - Die Kopie wird mittels qsort() aufsteigend sortiert. - * - Beim Durchlauf werden benachbarte Elemente verglichen. Da genau ein Wert - * doppelt vorkommt, finden wir ihn als erstes Paar gleicher Nachbarn. - * - * Fehlerbehandlung: - * - Bei ungültigen Parametern (numbers == NULL oder len < 2) wird 0 geliefert. - * - Bei Speicherfehlern beim Kopieren ebenfalls 0. - * - * Komplexität: - * - Sortieren in O(len * log(len)), anschließender Linearpass O(len). - * - * @param numbers Pointer auf das Eingabearray - * @param len Länge des Arrays (muss >= 2 sein) - * @return Der doppelte Wert; 0 bei Fehlern oder falls kein Duplikat gefunden wurde - * (gemäß Aufgabenstellung sollte aber genau ein Duplikat existieren). - */ -unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) -{ - if (numbers == NULL || len < 2) - return 0; - - // Kopie erstellen, damit das Original unangetastet bleibt - unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len); - if (copy == NULL) - return 0; - - memcpy(copy, numbers, sizeof(unsigned int) * len); - - // Sortieren der Kopie - qsort(copy, len, sizeof(unsigned int), compareUInt); - // Linearer Scan: erstes Paar identischer Nachbarn ist das Duplikat - unsigned int result = 0; - for (unsigned int i = 0; i + 1 < len; i++) - { - if (copy[i] == copy[i + 1]) { - result = copy[i]; - break; - } - } - - free(copy); - return result; -}