generated from freudenreichan/info2Praktikum-DobleSpiel
Unity-Tests numbers
This commit is contained in:
parent
461562b59b
commit
a3861d19ff
225
numbers.c
225
numbers.c
@ -1,26 +1,221 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "numbers.h"
|
|
||||||
#include "bintree.h"
|
|
||||||
|
|
||||||
//TODO: getDuplicate und createNumbers implementieren
|
/************************************************************
|
||||||
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
|
* BLOCK 0 – Zweck der Datei
|
||||||
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
|
* ----------------------------------------------------------
|
||||||
* Duplizieren eines zufälligen Eintrags im Array.
|
* Diese Datei liefert zwei Funktionen für das Spiel:
|
||||||
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
|
* - createNumbers(len): erzeugt ein Array mit len Zufallszahlen,
|
||||||
|
* in dem GENAU EINE Zahl doppelt vorkommt.
|
||||||
|
* - getDuplicate(numbers, len): findet effizient die doppelte Zahl.
|
||||||
|
*
|
||||||
|
* Technik:
|
||||||
|
* - Beim Erzeugen verhindert ein Binärsuchbaum (BST) Duplikate.
|
||||||
|
* - Beim Finden sortieren wir eine Kopie und vergleichen Nachbarn.
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
|
#include <stdlib.h> // malloc, free, rand
|
||||||
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
|
#include <stdio.h> // optional für Debug/printf
|
||||||
// creating random numbers.
|
#include <time.h> // time() für einmaliges srand-Seed
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
#include "numbers.h" // Deklarationen: createNumbers, getDuplicate
|
||||||
|
#include "bintree.h" // BST-API: addToTree, clearTree, CompareFctType
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* BLOCK 1 – Gemeinsame Vergleichsfunktion
|
||||||
|
* ----------------------------------------------------------
|
||||||
|
* compareUInt:
|
||||||
|
* - Definiert die Ordnung für unsigned int (aufsteigend).
|
||||||
|
* - Geeignet sowohl für den Binärbaum (addToTree)
|
||||||
|
* als auch für qsort.
|
||||||
|
* Rückgabewerte:
|
||||||
|
* - < 0 : a < b → im BST nach LINKS
|
||||||
|
* - = 0 : a == b → Duplikat
|
||||||
|
* - > 0 : a > b → im BST nach RECHTS
|
||||||
|
************************************************************/
|
||||||
|
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;
|
||||||
|
if (va > vb) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* BLOCK 2 – Zahlen erzeugen: createNumbers(len)
|
||||||
|
* ----------------------------------------------------------
|
||||||
|
* Ziel:
|
||||||
|
* - Ein Array mit len Zufallszahlen im Bereich [1 .. 2*len].
|
||||||
|
* - Zuerst ALLE eindeutig (via BST geprüft).
|
||||||
|
* - Danach GENAU EINE Zahl absichtlich duplizieren.
|
||||||
|
* - Zum Schluss das Array gleichverteilt mischen (Fisher–Yates).
|
||||||
|
*
|
||||||
|
* Rückgabe:
|
||||||
|
* - Pointer auf dynamisch allokiertes Array (Caller muss free).
|
||||||
|
* - NULL bei Fehlern (z. B. len < 2, malloc/Insert-Fehler).
|
||||||
|
************************************************************/
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int *createNumbers(unsigned int len)
|
||||||
{
|
{
|
||||||
|
/***********************
|
||||||
|
* 2.1 Vorbedingungen & Speicher
|
||||||
|
***********************/
|
||||||
|
if (len < 2) // Ein Duplikat macht erst ab 2 Elementen Sinn
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
|
if (!numbers) // Speicherfehler
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 2.2 Einmaliges Zufalls-Seed
|
||||||
|
* (falls main() nicht seedet, sorgen wir einmalig dafür)
|
||||||
|
***********************/
|
||||||
|
static int seeded = 0; // Merker: srand nur einmal pro Prozess
|
||||||
|
if (!seeded) {
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
seeded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
/***********************
|
||||||
|
* 2.3 BST-Setup & Wertebereich
|
||||||
|
***********************/
|
||||||
|
TreeNode *root = NULL; // Leerer Binärbaum zum Duplikat-Check
|
||||||
|
unsigned int range = 2 * len; // Zahlenbereich: 1..2*len
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 2.4 len-1 EINDEUTIGE Zahlen erzeugen
|
||||||
|
* – jede Zahl sofort gegen den BST prüfen
|
||||||
|
***********************/
|
||||||
|
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
|
||||||
|
val = (unsigned int)(rand() % range) + 1; // Kandidat in [1..2*len]
|
||||||
|
|
||||||
|
// Versuch, val in den Baum einzufügen (Kopie wird im Knoten gespeichert)
|
||||||
|
TreeNode *newRoot = addToTree(root, &val, sizeof(val), compareUInt, &isDup);
|
||||||
|
|
||||||
|
// Fehlerfall: Es wäre ein neuer Knoten, aber newRoot ist NULL (z. B. malloc-Fehler)
|
||||||
|
if (newRoot == NULL && isDup == 0) {
|
||||||
|
free(numbers); // Array freigeben
|
||||||
|
clearTree(root); // bisherige Baumknoten freigeben
|
||||||
|
return NULL; // sauber abbrechen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wurzel ggf. aktualisieren (z. B. wenn Baum vorher leer war)
|
||||||
|
if (newRoot) {
|
||||||
|
root = newRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDup) {
|
||||||
|
// Wert war eindeutig → ins Array übernehmen und weiter zum nächsten i
|
||||||
|
numbers[i] = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// sonst: Duplikat → neue Zufallszahl probieren
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 2.5 GENAU EIN Duplikat erzeugen
|
||||||
|
* – eine der bestehenden Zahlen zufällig wählen und erneut eintragen
|
||||||
|
***********************/
|
||||||
|
unsigned int idx = (unsigned int)(rand() % (len - 1)); // Quelle in [0..len-2]
|
||||||
|
numbers[len - 1] = numbers[idx]; // Duplikat absichtlich erzeugt
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 2.6 Gleichverteiltes Mischen (Fisher–Yates)
|
||||||
|
***********************/
|
||||||
|
for (unsigned int i = len - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
unsigned int j = (unsigned int)(rand() % (i + 1)); // j ∈ [0..i]
|
||||||
|
unsigned int tmp = numbers[i];
|
||||||
|
numbers[i] = numbers[j];
|
||||||
|
numbers[j] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 2.7 Aufräumen & Rückgabe
|
||||||
|
***********************/
|
||||||
|
clearTree(root); // BST wird nicht mehr gebraucht
|
||||||
|
return numbers; // Ownership des Arrays liegt beim Aufrufer (free(numbers))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* BLOCK 3 – Duplikat finden: getDuplicate(numbers, len)
|
||||||
|
* ----------------------------------------------------------
|
||||||
|
* Idee:
|
||||||
|
* - Original-Array unangetastet lassen → KOPIE erstellen.
|
||||||
|
* - Kopie aufsteigend sortieren (qsort mit demselben Comparator).
|
||||||
|
* - Ein linearer Durchlauf findet das erste Paar identischer Nachbarn.
|
||||||
|
*
|
||||||
|
* Rückgabe:
|
||||||
|
* - die doppelte Zahl
|
||||||
|
* - 0 bei Fehlern (z. B. ungültige Parameter, malloc-Fehler).
|
||||||
|
************************************************************/
|
||||||
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
||||||
{
|
{
|
||||||
|
/***********************
|
||||||
|
* 3.1 Vorbedingungen & Kopie allokieren
|
||||||
|
***********************/
|
||||||
|
if (!numbers || len < 2) // ungültig oder zu kurz
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
||||||
|
if (!copy) // Speicherfehler
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(copy, numbers, sizeof(unsigned int) * len); // Original in Kopie übertragen
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 3.2 Kopie sortieren (qsort + compareUInt)
|
||||||
|
***********************/
|
||||||
|
qsort(copy, len, sizeof(unsigned int), compareUInt);
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 3.3 Nachbarvergleich: erstes Paar gleicher Werte = Duplikat
|
||||||
|
***********************/
|
||||||
|
unsigned int result = 0;
|
||||||
|
for (unsigned int i = 0; i + 1 < len; i++)
|
||||||
|
{
|
||||||
|
if (copy[i] == copy[i + 1]) {
|
||||||
|
result = copy[i];
|
||||||
|
break; // Duplikat gefunden → fertig
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* 3.4 Aufräumen & Rückgabe
|
||||||
|
***********************/
|
||||||
|
free(copy); // Kopie freigeben
|
||||||
|
return result; // 0, falls (unerwartet) kein Duplikat gefunden
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* BLOCK 4 – Hinweise für die Vorstellung
|
||||||
|
* ----------------------------------------------------------
|
||||||
|
* Ownership:
|
||||||
|
* - Das von createNumbers zurückgegebene Array muss vom Aufrufer
|
||||||
|
* später mit free(numbers) freigegeben werden.
|
||||||
|
*
|
||||||
|
* Fehlerbehandlung:
|
||||||
|
* - Bei jedem Fehlerpfad werden ALLLE angelegten Ressourcen sauber
|
||||||
|
* freigegeben (Array/Kopie/Baum).
|
||||||
|
*
|
||||||
|
* Komplexität:
|
||||||
|
* - Erzeugen: O(n log n) durch BST-Einfügen + O(n) fürs Shuffle.
|
||||||
|
* - Finden: O(n log n) durch qsort + O(n) für den Nachbarvergleich.
|
||||||
|
*
|
||||||
|
* Zusammenarbeit:
|
||||||
|
* - addToTree setzt bei Gleichheit isDuplicate=1 (Duplikat),
|
||||||
|
* und liefert bei neuen Werten die (ggf. neue) Wurzel zurück.
|
||||||
|
* - clearTree gibt ALLE Knoten inkl. Datenkopien frei.
|
||||||
|
************************************************************/
|
||||||
|
|||||||
@ -17,28 +17,21 @@
|
|||||||
* @param b Pointer auf einen unsigned int-Wert (rechter Operand)
|
* @param b Pointer auf einen unsigned int-Wert (rechter Operand)
|
||||||
* @return -1, falls *a < *b; 1, falls *a > *b; 0, falls *a == *b
|
* @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)
|
static int compareUInt(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
unsigned int va = *(const unsigned int *)a;
|
unsigned int va = *(const unsigned int *)a;
|
||||||
unsigned int vb = *(const unsigned int *)b;
|
unsigned int vb = *(const unsigned int *)b;
|
||||||
if (va < vb) return -1;
|
if (va < vb) return -1; // links
|
||||||
if (va > vb) return 1;
|
if (va > vb) return 1; // rechts
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Vergleichsfunktion für qsort() zur Sortierung von unsigned int-Arrays.
|
|
||||||
*
|
|
||||||
* @param a Pointer auf einen Arrayeintrag
|
|
||||||
* @param b Pointer auf einen Arrayeintrag
|
|
||||||
* @return -1, 0, 1 analog zu compareUInt()
|
|
||||||
*/
|
|
||||||
static int qsort_uint_cmp(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;
|
|
||||||
if (va > vb) return 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,13 +47,16 @@ static int qsort_uint_cmp(const void *a, const void *b)
|
|||||||
* - Anschließend wird eine der bereits erzeugten Zahlen zufällig ausgewählt und
|
* - 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.
|
* noch einmal an das Ende des Arrays geschrieben, um das geforderte Duplikat sicherzustellen.
|
||||||
* - Zum Schluss wird das gesamte Array mittels Fisher–Yates-Algorithmus gemischt.
|
* - Zum Schluss wird das gesamte Array mittels Fisher–Yates-Algorithmus gemischt.
|
||||||
*
|
|
||||||
|
|
||||||
|
|
||||||
* Fehlerbehandlung:
|
* Fehlerbehandlung:
|
||||||
* - Bei len < 2 wird NULL zurückgegeben, da das Problem ein Duplikat erfordert.
|
* - 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.
|
* - Bei Speicher- oder Baum-Insertionsfehlern wird aufgeräumt und NULL zurückgegeben.
|
||||||
* Wichtig: Der Baumzeiger root wird erst nach erfolgreichem Insert aktualisiert,
|
* Wichtig: Der Baumzeiger root wird erst nach erfolgreichem Insert aktualisiert,
|
||||||
* um im Fehlerfall kein bereits aufgebautes Teilbaum-Objekt zu verlieren.
|
* um im Fehlerfall kein bereits aufgebautes Teilbaum-Objekt zu verlieren.
|
||||||
*
|
|
||||||
|
|
||||||
* Randbedingungen / Annahmen:
|
* Randbedingungen / Annahmen:
|
||||||
* - addToTree(root, &val, sizeof(val), compareUInt, &isDup) setzt isDup:
|
* - addToTree(root, &val, sizeof(val), compareUInt, &isDup) setzt isDup:
|
||||||
* isDup == 1 bedeutet „Duplikat gefunden, Baum unverändert“,
|
* isDup == 1 bedeutet „Duplikat gefunden, Baum unverändert“,
|
||||||
@ -75,6 +71,8 @@ static int qsort_uint_cmp(const void *a, const void *b)
|
|||||||
* @param len Anzahl der zu erzeugenden Werte (muss >= 2 sein)
|
* @param len Anzahl der zu erzeugenden Werte (muss >= 2 sein)
|
||||||
* @return Pointer auf ein Array mit len Einträgen bei Erfolg; NULL bei Fehlern
|
* @return Pointer auf ein Array mit len Einträgen bei Erfolg; NULL bei Fehlern
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
unsigned int *createNumbers(unsigned int len)
|
unsigned int *createNumbers(unsigned int len)
|
||||||
{
|
{
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
@ -84,9 +82,12 @@ unsigned int *createNumbers(unsigned int len)
|
|||||||
if (numbers == NULL)
|
if (numbers == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
// Zufallszahlengenerator nur einmal pro Prozess initialisieren.
|
// Zufallszahlengenerator nur einmal pro Prozess initialisieren.
|
||||||
// Hintergrund: Wird createNumbers mehrfach schnell hintereinander gerufen,
|
// Hintergrund: Wird createNumbers mehrfach schnell hintereinander gerufen,
|
||||||
// kann time(NULL) identische Seeds liefern und damit identische Zahlenfolgen erzeugen.
|
// kann time(NULL) identische Seeds liefern und damit identische Zahlenfolgen erzeugen.
|
||||||
|
|
||||||
|
|
||||||
static int seeded = 0;
|
static int seeded = 0;
|
||||||
if (!seeded) {
|
if (!seeded) {
|
||||||
srand((unsigned int)time(NULL));
|
srand((unsigned int)time(NULL));
|
||||||
@ -182,8 +183,7 @@ unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
|||||||
memcpy(copy, numbers, sizeof(unsigned int) * len);
|
memcpy(copy, numbers, sizeof(unsigned int) * len);
|
||||||
|
|
||||||
// Sortieren der Kopie
|
// Sortieren der Kopie
|
||||||
qsort(copy, len, sizeof(unsigned int), qsort_uint_cmp);
|
qsort(copy, len, sizeof(unsigned int), compareUInt);
|
||||||
|
|
||||||
// Linearer Scan: erstes Paar identischer Nachbarn ist das Duplikat
|
// Linearer Scan: erstes Paar identischer Nachbarn ist das Duplikat
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
for (unsigned int i = 0; i + 1 < len; i++)
|
for (unsigned int i = 0; i + 1 < len; i++)
|
||||||
|
|||||||
221
numbers_test3.c
221
numbers_test3.c
@ -1,221 +0,0 @@
|
|||||||
|
|
||||||
/************************************************************
|
|
||||||
* BLOCK 0 – Zweck der Datei
|
|
||||||
* ----------------------------------------------------------
|
|
||||||
* Diese Datei liefert zwei Funktionen für das Spiel:
|
|
||||||
* - createNumbers(len): erzeugt ein Array mit len Zufallszahlen,
|
|
||||||
* in dem GENAU EINE Zahl doppelt vorkommt.
|
|
||||||
* - getDuplicate(numbers, len): findet effizient die doppelte Zahl.
|
|
||||||
*
|
|
||||||
* Technik:
|
|
||||||
* - Beim Erzeugen verhindert ein Binärsuchbaum (BST) Duplikate.
|
|
||||||
* - Beim Finden sortieren wir eine Kopie und vergleichen Nachbarn.
|
|
||||||
************************************************************/
|
|
||||||
|
|
||||||
#include <stdlib.h> // malloc, free, rand
|
|
||||||
#include <stdio.h> // optional für Debug/printf
|
|
||||||
#include <time.h> // time() für einmaliges srand-Seed
|
|
||||||
#include <string.h> // memcpy
|
|
||||||
#include "numbers.h" // Deklarationen: createNumbers, getDuplicate
|
|
||||||
#include "bintree.h" // BST-API: addToTree, clearTree, CompareFctType
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* BLOCK 1 – Gemeinsame Vergleichsfunktion
|
|
||||||
* ----------------------------------------------------------
|
|
||||||
* compareUInt:
|
|
||||||
* - Definiert die Ordnung für unsigned int (aufsteigend).
|
|
||||||
* - Geeignet sowohl für den Binärbaum (addToTree)
|
|
||||||
* als auch für qsort.
|
|
||||||
* Rückgabewerte:
|
|
||||||
* - < 0 : a < b → im BST nach LINKS
|
|
||||||
* - = 0 : a == b → Duplikat
|
|
||||||
* - > 0 : a > b → im BST nach RECHTS
|
|
||||||
************************************************************/
|
|
||||||
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;
|
|
||||||
if (va > vb) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* BLOCK 2 – Zahlen erzeugen: createNumbers(len)
|
|
||||||
* ----------------------------------------------------------
|
|
||||||
* Ziel:
|
|
||||||
* - Ein Array mit len Zufallszahlen im Bereich [1 .. 2*len].
|
|
||||||
* - Zuerst ALLE eindeutig (via BST geprüft).
|
|
||||||
* - Danach GENAU EINE Zahl absichtlich duplizieren.
|
|
||||||
* - Zum Schluss das Array gleichverteilt mischen (Fisher–Yates).
|
|
||||||
*
|
|
||||||
* Rückgabe:
|
|
||||||
* - Pointer auf dynamisch allokiertes Array (Caller muss free).
|
|
||||||
* - NULL bei Fehlern (z. B. len < 2, malloc/Insert-Fehler).
|
|
||||||
************************************************************/
|
|
||||||
unsigned int *createNumbers(unsigned int len)
|
|
||||||
{
|
|
||||||
/***********************
|
|
||||||
* 2.1 Vorbedingungen & Speicher
|
|
||||||
***********************/
|
|
||||||
if (len < 2) // Ein Duplikat macht erst ab 2 Elementen Sinn
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
unsigned int *numbers = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
|
||||||
if (!numbers) // Speicherfehler
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.2 Einmaliges Zufalls-Seed
|
|
||||||
* (falls main() nicht seedet, sorgen wir einmalig dafür)
|
|
||||||
***********************/
|
|
||||||
static int seeded = 0; // Merker: srand nur einmal pro Prozess
|
|
||||||
if (!seeded) {
|
|
||||||
srand((unsigned int)time(NULL));
|
|
||||||
seeded = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.3 BST-Setup & Wertebereich
|
|
||||||
***********************/
|
|
||||||
TreeNode *root = NULL; // Leerer Binärbaum zum Duplikat-Check
|
|
||||||
unsigned int range = 2 * len; // Zahlenbereich: 1..2*len
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.4 len-1 EINDEUTIGE Zahlen erzeugen
|
|
||||||
* – jede Zahl sofort gegen den BST prüfen
|
|
||||||
***********************/
|
|
||||||
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
|
|
||||||
val = (unsigned int)(rand() % range) + 1; // Kandidat in [1..2*len]
|
|
||||||
|
|
||||||
// Versuch, val in den Baum einzufügen (Kopie wird im Knoten gespeichert)
|
|
||||||
TreeNode *newRoot = addToTree(root, &val, sizeof(val), compareUInt, &isDup);
|
|
||||||
|
|
||||||
// Fehlerfall: Es wäre ein neuer Knoten, aber newRoot ist NULL (z. B. malloc-Fehler)
|
|
||||||
if (newRoot == NULL && isDup == 0) {
|
|
||||||
free(numbers); // Array freigeben
|
|
||||||
clearTree(root); // bisherige Baumknoten freigeben
|
|
||||||
return NULL; // sauber abbrechen
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wurzel ggf. aktualisieren (z. B. wenn Baum vorher leer war)
|
|
||||||
if (newRoot) {
|
|
||||||
root = newRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDup) {
|
|
||||||
// Wert war eindeutig → ins Array übernehmen und weiter zum nächsten i
|
|
||||||
numbers[i] = val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// sonst: Duplikat → neue Zufallszahl probieren
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.5 GENAU EIN Duplikat erzeugen
|
|
||||||
* – eine der bestehenden Zahlen zufällig wählen und erneut eintragen
|
|
||||||
***********************/
|
|
||||||
unsigned int idx = (unsigned int)(rand() % (len - 1)); // Quelle in [0..len-2]
|
|
||||||
numbers[len - 1] = numbers[idx]; // Duplikat absichtlich erzeugt
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.6 Gleichverteiltes Mischen (Fisher–Yates)
|
|
||||||
***********************/
|
|
||||||
for (unsigned int i = len - 1; i > 0; i--)
|
|
||||||
{
|
|
||||||
unsigned int j = (unsigned int)(rand() % (i + 1)); // j ∈ [0..i]
|
|
||||||
unsigned int tmp = numbers[i];
|
|
||||||
numbers[i] = numbers[j];
|
|
||||||
numbers[j] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 2.7 Aufräumen & Rückgabe
|
|
||||||
***********************/
|
|
||||||
clearTree(root); // BST wird nicht mehr gebraucht
|
|
||||||
return numbers; // Ownership des Arrays liegt beim Aufrufer (free(numbers))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* BLOCK 3 – Duplikat finden: getDuplicate(numbers, len)
|
|
||||||
* ----------------------------------------------------------
|
|
||||||
* Idee:
|
|
||||||
* - Original-Array unangetastet lassen → KOPIE erstellen.
|
|
||||||
* - Kopie aufsteigend sortieren (qsort mit demselben Comparator).
|
|
||||||
* - Ein linearer Durchlauf findet das erste Paar identischer Nachbarn.
|
|
||||||
*
|
|
||||||
* Rückgabe:
|
|
||||||
* - die doppelte Zahl
|
|
||||||
* - 0 bei Fehlern (z. B. ungültige Parameter, malloc-Fehler).
|
|
||||||
************************************************************/
|
|
||||||
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len)
|
|
||||||
{
|
|
||||||
/***********************
|
|
||||||
* 3.1 Vorbedingungen & Kopie allokieren
|
|
||||||
***********************/
|
|
||||||
if (!numbers || len < 2) // ungültig oder zu kurz
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned int *copy = (unsigned int *)malloc(sizeof(unsigned int) * len);
|
|
||||||
if (!copy) // Speicherfehler
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memcpy(copy, numbers, sizeof(unsigned int) * len); // Original in Kopie übertragen
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 3.2 Kopie sortieren (qsort + compareUInt)
|
|
||||||
***********************/
|
|
||||||
qsort(copy, len, sizeof(unsigned int), compareUInt);
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 3.3 Nachbarvergleich: erstes Paar gleicher Werte = Duplikat
|
|
||||||
***********************/
|
|
||||||
unsigned int result = 0;
|
|
||||||
for (unsigned int i = 0; i + 1 < len; i++)
|
|
||||||
{
|
|
||||||
if (copy[i] == copy[i + 1]) {
|
|
||||||
result = copy[i];
|
|
||||||
break; // Duplikat gefunden → fertig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* 3.4 Aufräumen & Rückgabe
|
|
||||||
***********************/
|
|
||||||
free(copy); // Kopie freigeben
|
|
||||||
return result; // 0, falls (unerwartet) kein Duplikat gefunden
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
|
||||||
* BLOCK 4 – Hinweise für die Vorstellung
|
|
||||||
* ----------------------------------------------------------
|
|
||||||
* Ownership:
|
|
||||||
* - Das von createNumbers zurückgegebene Array muss vom Aufrufer
|
|
||||||
* später mit free(numbers) freigegeben werden.
|
|
||||||
*
|
|
||||||
* Fehlerbehandlung:
|
|
||||||
* - Bei jedem Fehlerpfad werden ALLLE angelegten Ressourcen sauber
|
|
||||||
* freigegeben (Array/Kopie/Baum).
|
|
||||||
*
|
|
||||||
* Komplexität:
|
|
||||||
* - Erzeugen: O(n log n) durch BST-Einfügen + O(n) fürs Shuffle.
|
|
||||||
* - Finden: O(n log n) durch qsort + O(n) für den Nachbarvergleich.
|
|
||||||
*
|
|
||||||
* Zusammenarbeit:
|
|
||||||
* - addToTree setzt bei Gleichheit isDuplicate=1 (Duplikat),
|
|
||||||
* und liefert bei neuen Werten die (ggf. neue) Wurzel zurück.
|
|
||||||
* - clearTree gibt ALLE Knoten inkl. Datenkopien frei.
|
|
||||||
************************************************************/
|
|
||||||
Loading…
x
Reference in New Issue
Block a user