generated from freudenreichan/info2Praktikum-DobleSpiel
numbers_test2.c gelöscht
This commit is contained in:
parent
a3861d19ff
commit
720769aef5
199
numbers_test2.c
199
numbers_test2.c
@ -1,199 +0,0 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user