info2aufgabe3/numbers.c
shobayoeniolasi99076 d124049c95 duplicate removed
2026-06-15 12:44:45 +02:00

150 lines
5.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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.
* 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. */
// Comparison function for unsigned integers used in BST and sorting operations.
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
// This is an internal function (static) since it's not part of the public API.
static int compareUnsignedInts(const void *a, const void *b)
{
unsigned int valA = *(const unsigned int *)a;
unsigned int valB = *(const unsigned int *)b;
// Safe comparison without overflow concerns for our range
if (valA < valB) return -1;
if (valA > valB) 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 the implementation of the binary search tree to check for possible duplicates while
// creating random numbers.
//
// Algorithm:
// 1. Generate len-1 unique random numbers using the BST for duplicate detection
// 2. Randomly duplicate one of those numbers by inserting it at a random position
// 3. Final array has len entries with exactly one value appearing twice
unsigned int *createNumbers(unsigned int len)
{
// Step 1: Validate input - we need at least 2 elements to create a duplicate
if (len < 2)
{
return NULL;
}
// Step 2: Allocate memory for the final array (len elements total)
unsigned int *numbers = (unsigned int *)malloc(len * sizeof(unsigned int));
if (numbers == NULL)
{
return NULL;
}
// Step 3: Create binary search tree to track generated numbers and prevent accidental duplicates
// Note: Random seed should be initialized once in main() with srand(time(NULL))
// Calling srand() here would reset the seed each time, reducing randomness
TreeNode *usedNumbers = NULL;
// Step 4: Generate len-1 unique random numbers (we'll add one duplicate later)
unsigned int arrayIndex = 0;
while (arrayIndex < len - 1)
{
// Generate random number in range [1, 2×len]
unsigned int randomNumber = (rand() % (2 * len)) + 1;
// Check if this number was already generated
int isDuplicate = 0;
usedNumbers = addToTree(usedNumbers, &randomNumber, sizeof(unsigned int), compareUnsignedInts, &isDuplicate);
if (usedNumbers == NULL) // checks if addTOTree failed
{
free(numbers);
return NULL;
}
// If new number, add to result array; if duplicate, retry
if (isDuplicate == 0)
{
numbers[arrayIndex] = randomNumber;
arrayIndex++;
}
}
// Step 5: Pick a random value from our generated numbers to duplicate
unsigned int indexToDuplicate = rand() % (len - 1);
unsigned int valueToDuplicate = numbers[indexToDuplicate];
// Step 6: Pick a random position to insert the duplicate (anywhere in the array)
unsigned int insertPos = rand() % len;
// Step 7: Shift elements right to make room for the duplicate
for (unsigned int i = len - 1; i > insertPos; i--)
{
numbers[i] = numbers[i - 1];
}
// Step 8: Insert the duplicate at the chosen position
numbers[insertPos] = valueToDuplicate;
// Step 9: Clean up the binary search tree (we don't need it anymore)
clearTree(usedNumbers);
// Return the array with len elements (len-1 unique + 1 duplicate)
return numbers;
}
// Returns only the only number in numbers which is present twice. Returns zero on errors.
//
// Algorithm:
// 1. Create a copy of the array to avoid modifying the input
// 2. Sort the copy using qsort()
// 3. Compare adjacent elements to find the duplicate
// 4. Return the duplicate value, or 0 on error
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len)
{
// Step 1: Input validation - need at least 2 elements to have a duplicate
if (numbers == NULL || len < 2)
{
return 0;
}
// Step 2: Create a copy of the array to sort (we don't modify the input)
unsigned int *sorted = (unsigned int *)malloc(len * sizeof(unsigned int));
if (sorted == NULL)
{
return 0;
}
// Step 3: Copy the array
memcpy(sorted, numbers, len * sizeof(unsigned int));
// Step 4: Sort the copy using the shared comparison function
qsort(sorted, len, sizeof(unsigned int), compareUnsignedInts);
// Step 5: Compare adjacent elements to find the duplicate
for (unsigned int i = 0; i < len - 1; i++)
{
if (sorted[i] == sorted[i + 1])
{
// Found the duplicate!
unsigned int result = sorted[i];
free(sorted);
return result;
}
}
// Step 6: No duplicate found (should not happen if input is valid)
free(sorted);
return 0;
}