2010-07-27 13 views
9

Aquí hay una implementación en C de Fisher-Yates que quiero usar en una rutina de barajado de barajas. ¿Estoy haciendo esto correctamente (n = longitud de la matriz)?¿Es correcta la implementación C de la compilación de Fisher-Yates?

Nota: El ciclo do-while intenta corregir el sesgo del módulo (consulte here). Agrega un poco de sobrecarga al procedimiento y podría eliminarse si no le importa el sesgo de bits bajos.

void shuffle(int *array, int n) { 

    int i, j, tmp, upper_bound; 

    srand(time(NULL)); 

    for (i = n - 1; i > 0; i--) { 

    upper_bound = RAND_MAX - ((RAND_MAX % (i + 1)) + 1); 

    do { 
     j = rand() % (i + 1); 
    } while (j > upper_bound); 

    tmp = array[j]; 
    array[j] = array[i]; 
    array[i] = tmp; 
    } 
} 
+0

Me vino a la cabeza que 'int lim = RAND_MAX-i;' ... '} while (j> upper_bound && --lim);' podría ser una forma adecuada de atrapar el _it_ _can_ _never_ _happen_ caso de números aleatorios repetidos fuera de rango. – nategoose

Respuesta

24

En primer lugar, se debe extraer el código para generar un número aleatorio que se distribuye por igual entre 0 (ambos inclusive) y n (exclusivo) a una función separada. Esa es una buena tarea de trabajo que necesitarás en otro lugar, también.

En segundo lugar, no llamaría a srand dentro de la función shuffle pero dependerá de la persona que llama al inicializar el generador de números aleatorios. De esa manera puedes barajar un mazo más de una vez en un segundo.

En tercer lugar, debe hacer la prueba para j > upper_bound antes de dividir por i + 1. Es poco probable que i esté cerca de RAND_MAX.

static int rand_int(int n) { 
    int limit = RAND_MAX - RAND_MAX % n; 
    int rnd; 

    do { 
    rnd = rand(); 
    } while (rnd >= limit); 
    return rnd % n; 
} 

void shuffle(int *array, int n) { 
    int i, j, tmp; 

    for (i = n - 1; i > 0; i--) { 
    j = rand_int(i + 1); 
    tmp = array[j]; 
    array[j] = array[i]; 
    array[i] = tmp; 
    } 
} 

Para comprobar si esta aplicación puede ser correcta, es necesario asegurarse de que usted le pidió al generador de números aleatorios para log2(n!) bits de aleatoriedad. En otras palabras, el producto de todos los n s otorgados a la función rand_int debe ser n!.

+0

+1 para el comentario sobre la siembra. También es un problema de "seguridad" si los usuarios externos de su código pueden predecir/influir en su reproducción aleatoria controlando el tiempo. – Darron

+0

¿Qué significa que la persona que llama inicializa el número aleatorio? ¿Eso es como depender de los movimientos del mouse de la persona que llama o algo así? – MikeRand

+3

No. Lo que significa es que: cualquier programador experimentado no esperaría que una rutina llamada 'shuffle' restablezca el generador de números aleatorios a un estado específico. Eso simplemente no está incluido en la palabra 'shuffle'. El único punto donde debe llamar 'srand()' está en la función 'main'. Como guía, pregúntese: "¿Qué hace esta función?" La respuesta para la función 'shuffle' sería:" Mezcla la matriz dada * y reinicia el generador de números aleatorios *. " Esto solo debería sonar lo suficientemente extraño. –

Cuestiones relacionadas