How to retrieve k random numbers from a vector of unknown size at compile time in C

1 Answer

0 votes
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
 * get_random_sample()
 *
 * Selects k unique random elements from an input array.
 *
 * Parameters:
 *   array       - source array
 *   array_size  - number of elements in the source array
 *   k           - number of random elements to retrieve
 *   result      - output array of size at least k
 *
 * Notes:
 *   - Sampling is done without replacement.
 *   - The original array is not modified.
 *   - Uses a partial Fisher-Yates shuffle, which is O(k).
 */
int get_random_sample(
    const int *array,
    size_t array_size,
    size_t k,
    int *result)
{
    if (array == NULL || result == NULL) {
        return -1;
    }

    if (k > array_size) {
        return -1;
    }

    /*
     * Create a working copy because we do not
     * want to modify the caller's array.
     */
    int *temp = malloc(array_size * sizeof(int));

    if (temp == NULL) {
        return -1;
    }

    for (size_t i = 0; i < array_size; ++i) {
        temp[i] = array[i];
    }

    /*
     * Partial Fisher-Yates shuffle:
     *
     * After each iteration, one random element
     * is moved into its final position.
     *
     * We only perform k iterations because we
     * only need k random values.
     */
    for (size_t i = 0; i < k; ++i) {
        size_t random_index =
            i + (size_t)(rand() % (array_size - i));

        int tmp = temp[i];
        temp[i] = temp[random_index];
        temp[random_index] = tmp;
    }

    for (size_t i = 0; i < k; ++i) {
        result[i] = temp[i];
    }

    free(temp);

    return 0;
}

int main(void)
{
    /* Array size is known only at runtime. */
    int numbers[] = {
        10, 20, 30, 40, 50,
        60, 70, 80, 90, 100
    };

    size_t array_size =
        sizeof(numbers) / sizeof(numbers[0]);

    size_t k = 4;

    int sample[4];

    /* Seed the random number generator once. */
    srand((unsigned int)time(NULL));

    if (get_random_sample(
            numbers,
            array_size,
            k,
            sample) != 0)
    {
        fprintf(stderr, "Failed to retrieve sample.\n");
        return EXIT_FAILURE;
    }

    printf("Random sample:\n");

    for (size_t i = 0; i < k; ++i) {
        printf("%d ", sample[i]);
    }

    return EXIT_SUCCESS;
}


/*
run:

Random sample:
70 30 60 20 

*/

 



answered Oct 2 by avibootz
...