161 lines
5.5 KiB
C
161 lines
5.5 KiB
C
#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 the binary search tree
|
||
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
|
||
// This function is passed to addToTree to determine ordering
|
||
int compareUnsignedInts(const void *a, const void *b)
|
||
{
|
||
unsigned int valA = *(const unsigned int *)a;
|
||
unsigned int valB = *(const unsigned int *)b;
|
||
|
||
// Simple subtraction works for unsigned integers in this case
|
||
// (Note: in general subtraction can overflow, but our range is small)
|
||
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 your 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)
|
||
{
|
||
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;
|
||
}
|
||
|
||
// Comparison function for qsort to sort unsigned integers in ascending order
|
||
// Returns: <0 if a < b, 0 if a == b, >0 if a > b
|
||
static int compareUnsigned(const void *a, const void *b)
|
||
{
|
||
unsigned int valA = *(const unsigned int *)a;
|
||
unsigned int valB = *(const unsigned int *)b;
|
||
|
||
if (valA < valB) return -1;
|
||
if (valA > valB) return 1;
|
||
return 0;
|
||
}
|
||
|
||
// 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
|
||
qsort(sorted, len, sizeof(unsigned int), compareUnsigned);
|
||
|
||
// 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;
|
||
} |