Crear secuencia de números aleatorios sin repeticiones

Duplicar:

¿Números aleatorios únicos en O (1)?

Quiero un generador de números pseudoaleatorios que pueda generar números sin repeticiones en orden aleatorio.

Por ejemplo:

al azar (10)

podría devolver 5, 9, 1, 4, 2, 8, 3, 7, 6, 10

¿Hay una forma mejor de hacerlo que no sea hacer el rango de números y mezclarlos, o verificar la lista generada para las repeticiones?


Editar:

También quiero que sea eficiente en la generación de grandes números sin todo el rango.


Editar:

Veo a todos sugiriendo algoritmos aleatorios. Pero si quiero generar un número aleatorio grande (1024 byte +), ese método tomaría mucha más memoria que si acabara de usar un RNG regular y lo insertara en un Set hasta que tuviera una longitud específica, ¿no? No hay mejor algoritmo matemático para esto.

Puede estar interesado en un registro de desplazamiento de retroalimentación lineal. Solíamos construirlos con hardware, pero también los hice en software. Utiliza un registro de desplazamiento con algunos de los bits xor’ed y retroalimentados a la entrada, y si selecciona los “toques” correctos puede obtener una secuencia que es tan larga como el tamaño del registro. Es decir, un lfsr de 16 bits puede producir una secuencia de 65535 de largo sin repeticiones. Es estadísticamente aleatorio pero por supuesto eminentemente repetible. Además, si se hace mal, puedes obtener algunas secuencias vergonzosamente cortas. Si busca el lfsr, encontrará ejemplos de cómo construirlos correctamente (es decir, “longitud máxima”).

Una reproducción aleatoria es una forma perfectamente buena de hacerlo (siempre que no introduzca un sesgo utilizando el algoritmo ingenuo). Ver mezcla de Fisher-Yates .

Para asegurarse de que la lista no se repita, debería mantener una lista de números previamente devueltos. Como, por lo tanto, tiene que generar toda la lista al final del algoritmo, esto es equivalente en requisitos de almacenamiento para generar la lista ordenada y luego mezclar.

Más acerca de la mezcla aleatoria aquí: creación de una lista ordenada al azar de una lista ordenada

Sin embargo, si el rango de los números aleatorios es muy grande pero la cantidad de números requeridos es pequeña (ha insinuado que este es el requisito real en un comentario), genere una lista completa y mezclarla es un desperdicio. Una reproducción aleatoria en una gran matriz implica acceder a páginas de memoria virtual de una manera que (por definición) vencerá al sistema de paginación del sistema operativo (en una escala más pequeña, el mismo problema ocurriría con la memoria caché de la CPU).

En este caso, buscar en la lista hasta ahora será mucho más eficiente. Entonces, lo ideal sería usar heurística (determinada por experimento) para elegir la implementación correcta para los argumentos dados. (Disculpas por dar ejemplos en C # en lugar de C ++, pero ASFAC ++ B Me estoy entrenando para pensar en C #).

IEnumerable GenerateRandomNumbers(int range, int quantity) { int[] a = new int[quantity]; if (range < Threshold) { for (int n = 0; n < range; n++) a[n] = n; Shuffle(a); } else { HashSet used = new HashSet(); for (int n = 0; n < quantity; n++) { int r = Random(range); while (!used.Add(r)) r = Random(range); a[n] = r; } } return a; } 

El costo de hacer la verificación de números repetidos, el bucle mientras hay colisiones, etc. será costoso, pero es probable que exista algún valor de Threshold donde sea más rápido que la asignación para todo el rango.

Para requisitos de cantidad suficientemente pequeños, puede ser más rápido usar una matriz para búsquedas used y lineales en ella, debido a la localidad más grande, a una sobrecarga más baja, a la baratura de la comparación ...

También para grandes cantidades Y grandes rangos, puede ser preferible devolver un objeto que produce los números en la secuencia a petición, en lugar de asignar la matriz para los resultados por adelantado. Esto es muy fácil de implementar en C # gracias a la palabra clave yield return :

 IEnumerable ForLargeQuantityAndRange(int quantity, int range) { for (int n = 0; n < quantity; n++) { int r = Random(range); while (!used.Add(r)) r = Random(range); yield return r; } } 

Si se garantiza que un número aleatorio nunca se repetirá, ya no es aleatorio y la cantidad de aleatoriedad disminuye a medida que se generan los números (después de nueve números random(10) es bastante predecible e incluso después de solo ocho, tiene una probabilidad de 50-50).

Entiendo que no desee una mezcla para grandes rangos, ya que tendría que almacenar toda la lista para hacerlo.

En su lugar, use un hash pseudoaleatorio reversible. Luego ingrese los valores 0 1 2 3 4 5 6, etc. a su vez.

Hay infinitos números de hashes como este. No son demasiado difíciles de generar si están restringidos a una potencia de 2, pero se puede usar cualquier base.

Aquí hay uno que funcionaría, por ejemplo, si quisiera ver todos los valores de 2 ^ 32 32 bit. Es más fácil escribir porque el mod implícito 2 ^ 32 de la matemática entera funciona a su favor en este caso.

 unsigned int reversableHash(unsigned int x) { x*=0xDEADBEEF; x=x^(x>>17); x*=0x01234567; x+=0x88776655; x=x^(x>>4); x=x^(x>>9); x*=0x91827363; x=x^(x>>7); x=x^(x>>11); x=x^(x>>20); x*=0x77773333; return x; } 

Si no te molestan las propiedades de aleatoriedad mediocres y si la cantidad de elementos lo permite, entonces podrías usar un generador de números aleatorios congruenciales lineales .

Un shuffle es lo mejor que puedes hacer para números aleatorios en un rango específico sin repeticiones. La razón por la cual el método que describes (generar números aleatoriamente y ponerlos en un conjunto hasta que scopes una longitud específica) es menos eficiente debido a los duplicados. Teóricamente, ese algoritmo podría nunca terminar. En el mejor de los casos, terminará en un período de tiempo indeterminable, en comparación con una reproducción aleatoria, que siempre se ejecutará en un período de tiempo altamente predecible.


Respuesta a ediciones y comentarios:

Si, como lo indica en los comentarios, el rango de números es muy grande y desea seleccionar relativamente pocos al azar sin repeticiones, entonces la probabilidad de repeticiones disminuye rápidamente. Cuanto mayor sea la diferencia de tamaño entre el rango y el número de selecciones, menor será la probabilidad de repetir selecciones, y mejor será el rendimiento para el algoritmo de selección y verificación que describe en la pregunta.

¿Qué pasa con el uso de generador GUID (como en el de .NET). De acuerdo, no se garantiza que no haya duplicados, sin embargo, la oportunidad de obtener uno es bastante baja.

Esto se ha preguntado antes – ver mi respuesta a la pregunta anterior . En pocas palabras: puede usar un cifrado de bloques para generar una permutación segura (aleatoria) en cualquier rango que desee, sin tener que almacenar toda la permutación en ningún punto.

Si desea crear números aleatorios grandes (digamos, 64 bits o más) sin repeticiones, simplemente créelos. Si está utilizando un buen generador de números aleatorios, que en realidad tiene suficiente entropía, entonces las probabilidades de generar repeticiones son tan minúsculas que no vale la pena preocuparse.

Por ejemplo, al generar claves criptográficas, nadie realmente se molesta en verificar si ya han generado la misma clave antes; ya que confía en su generador de números aleatorios para que un atacante dedicado no pueda obtener la misma clave, ¿por qué esperaría que apareciera accidentalmente la misma clave?

Por supuesto, si tiene un generador de números aleatorios incorrecto (como la vulnerabilidad del generador de números aleatorios SSL de Debian ) o está generando números lo suficientemente pequeños como para que la paradoja de cumpleaños le brinde una alta probabilidad de colisión, entonces deberá hacer algo para asegurarse no obtienes repeticiones Pero para grandes números aleatorios con un buen generador, solo confíe en la probabilidad de no darle ninguna repetición.

A medida que genera sus números, use un filtro Bloom para detectar duplicados. Esto usaría una cantidad mínima de memoria. No habría necesidad de almacenar números anteriores en la serie.

La compensación es que su lista no puede ser exhaustiva en su rango. Si sus números son realmente del orden de 256 ^ 1024, eso no significa nada.

(Por supuesto, si son realmente aleatorios en esa escala, incluso molestarse en detectar duplicados es una pérdida de tiempo. Si cada computadora en la tierra generó un billón de números aleatorios de ese tamaño cada billón de años, la posibilidad de una colisión sigue siendo absoluta despreciable.)

Apoyo la respuesta de gbarry sobre el uso de un LFSR . Son muy eficientes y simples de implementar incluso en software y se garantiza que no se repetirán en (2 ^ N – 1) usos para un LFSR con un registro de desplazamiento de N bits.

Sin embargo, hay algunos inconvenientes: al observar un pequeño número de resultados del RNG, uno puede reconstruir el LFSR y predecir todos los valores que generará, lo que los hace no utilizables para la criptografía y en cualquier lugar donde se necesite un buen RNG. El segundo problema es que la palabra all zero o all one (en términos de bits) no es válida según la implementación de LFSR. El tercer problema que es relevante para su pregunta es que la cantidad máxima generada por el LFSR es siempre una potencia de 2 – 1 (o potencia de 2 – 2).

El primer inconveniente podría no ser un problema dependiendo de su aplicación. Según el ejemplo que dio, parece que no espera que el cero esté entre las respuestas; entonces, el segundo problema no parece relevante para su caso. El problema del valor máximo (y por lo tanto del rango) puede resolverse reutilizando el LFSR hasta que obtenga un número dentro de su rango. Aquí hay un ejemplo:

Digamos que quiere tener números entre 1 y 10 (como en su ejemplo). Utilizaría un LFSR de 4 bits que tiene un rango [1, 15] inclusive. Aquí hay un pseudo código sobre cómo obtener el número en el rango [1,10]:

 x = LFSR.getRandomNumber(); while (x > 10) { x = LFSR.getRandomNumber(); } 

Debe incrustar el código anterior en su RNG; para que la persona que llama no se preocupe por la implementación. Tenga en cuenta que esto ralentizaría su RNG si usa un gran registro de desplazamiento y el número máximo que desea no es una potencia de 2 – 1.

Mezclar N elementos no ocupa demasiada memoria … piénselo. Solo intercambia un elemento a la vez, por lo que la memoria máxima utilizada es la de N + 1 elementos.

Suponiendo que tiene un generador de números aleatorio o pseudoaleatorio, incluso si no se garantiza que devuelva valores únicos, puede implementar uno que devuelva valores únicos cada vez que utilice este código, suponiendo que el límite superior permanezca constante (es decir, siempre lo llame con random(10) , y no lo llames random(10); random(11) .

El código no verifica si hay errores. Puede agregarlo usted mismo si lo desea.
También requiere mucha memoria si desea una gran variedad de números.

 /* the function returns a random number between 0 and max -1 * not necessarily unique * I assume it's written */ int random(int max); /* the function returns a unique random number between 0 and max - 1 */ int unique_random(int max) { static int *list = NULL; /* contains a list of numbers we haven't returned */ static int in_progress = 0; /* 0 --> we haven't started randomizing numbers * 1 --> we have started randomizing numbers */ static int count; static prev_max = 0; // initialize the list if (!in_progress || (prev_max != max)) { if (list != NULL) { free(list); } list = malloc(sizeof(int) * max); prev_max = max; in_progress = 1; count = max - 1; int i; for (i = max - 1; i >= 0; --i) { list[i] = i; } } /* now choose one from the list */ int index = random(count); int retval = list[index]; /* now we throw away the returned value. * we do this by shortening the list by 1 * and replacing the element we returned with * the highest remaining number */ swap(&list[index], &list[count]); /* when the count reaches 0 we start over */ if (count == 0) { in_progress = 0; free(list); list = 0; } else { /* reduce the counter by 1 */ count--; } } /* swap two numbers */ void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } 

Supongamos que quiere generar una serie de 256 números aleatorios sin repeticiones.

  1. Cree un bloque de memoria de 256 bits (32 bytes) inicializado con ceros, llamémoslo b
  2. Su variable de bucle será n , la cantidad de números que aún no se ha generado
  3. Loop de n = 256 a n = 1
  4. Genera un número aleatorio r en el rango [0, n)
  5. Encuentre el r -ésimo bit cero en su bloque de memoria b , llamémoslo p
  6. Pon p en tu lista de resultados, una matriz llamada q
  7. Voltee la p -ésima bit en el bloque de memoria b a 1
  8. Después del n = 1 pase, ha terminado de generar su lista de números

Aquí hay un breve ejemplo de lo que estoy hablando, usando inicialmente n = 4:

 **Setup** b = 0000 q = [] **First loop pass, where n = 4** r = 2 p = 2 b = 0010 q = [2] **Second loop pass, where n = 3** r = 2 p = 3 b = 0011 q = [2, 3] **Third loop pass, where n = 2** r = 0 p = 0 b = 1011 q = [2, 3, 0] ** Fourth and final loop pass, where n = 1** r = 0 p = 1 b = 1111 q = [2, 3, 0, 1] 

Por favor revise las respuestas en

Generar secuencia de enteros en orden aleatorio sin construir toda la lista por adelantado

y también mi respuesta se encuentra allí como

  very simple random is 1+((power(r,x)-1) mod p) will be from 1 to p for values of x from 1 to p and will be random where r and p are prime numbers and r <> p. 

Hice una pregunta similar antes, pero la mía fue para todo el rango de una int. Buscar una función hash / Ordered Int / to / Shuffled Int /

 static std::unordered_set s; long l = 0; for(; !l && (s.end() != s.find(l)); l = generator()); v.insert(l); 

generador () es su generador de números aleatorios. Tira números siempre que la entrada no esté en su conjunto, luego agrega lo que encuentre en ella. Entiendes la idea.

Lo hice con long para el ejemplo, pero debes hacer una plantilla si tu PRNG está templado.

Alternativa es usar un PRNG criptográficamente seguro que tendrá una probabilidad muy baja de generar el doble del mismo número.

Si no se refiere a las propiedades estadísticas pobres de la secuencia generada, hay un método:

Digamos que quieres generar N números, cada uno de 1024 bits cada uno. Puede sacrificar algunos bits del número generado para ser “contador”.

Entonces usted genera cada número aleatorio, pero en algunos bits que usted elige pone contador binario codificado (de la variable, aumenta cada vez que se genera el siguiente número aleatorio).

Puede dividir ese número en bits individuales y colocarlo en algunos de los bits generados menos significativos.

De esta forma, está seguro de obtener un número único cada vez.

Quiero decir, por ejemplo, cada número generado tiene el siguiente aspecto: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyxxxxyxyyyyxxyxx donde x se toma directamente del generador, y y se toman de la variable del contador.

Twister Mersenne

Descripción de lo que se puede encontrar aquí en Wikipedia: Twister Mersenne

Mire la parte inferior de la página para ver las implementaciones en varios idiomas.

El problema es seleccionar una secuencia “aleatoria” de N números únicos del rango 1..M donde no hay restricción en la relación entre N y M (M podría ser mucho más grande, más o menos igual que N; pueden no ser relativamente primos).

Ampliando la respuesta del registro de desplazamiento de retroalimentación lineal: para un M dado, construya un LFSR máximo para la potencia más pequeña de dos que sea más grande que M. Entonces solo tome los números del LFSR arrojando números mayores que M. En promedio, lo hará arroje como máximo la mitad de los números generados (ya que por construcción más de la mitad del rango del LFSR es menor que M), entonces el tiempo de ejecución esperado para obtener un número es O (1). No está almacenando números generados previamente, por lo que el consumo de espacio también es O (1). Si realiza un ciclo antes de obtener N números, entonces M será menor que N (o el LFSR se construirá incorrectamente).

Puede encontrar los parámetros para LFSR de longitud máxima de hasta 168 bits aquí (de wikipedia): http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf

Aquí hay algunos códigos de Java:

/ ** * Genera una secuencia de números únicos “aleatorios” en [0, M) * @author dkoes * * /

clase pública UniqueRandom {long lfsr; máscara larga; largo máximo;

 private static long seed = 1; //indexed by number of bits private static int [][] taps = { null, // 0 null, // 1 null, // 2 {3,2}, //3 {4,3}, {5,3}, {6,5}, {7,6}, {8,6,5,4}, {9,5}, {10,7}, {11,9}, {12,6,4,1}, {13,4,3,1}, {14,5,3,1}, {15,14}, {16,15,13,4}, {17,14}, {18,11}, {19,6,2,1}, {20,17}, {21,19}, {22,21}, {23,18}, {24,23,22,17}, {25,22}, {26,6,2,1}, {27,5,2,1}, {28,25}, {29,27}, {30,6,4,1}, {31,28}, {32,22,2,1}, {33,20}, {34,27,2,1}, {35,33}, {36,25}, {37,5,4,3,2,1}, {38,6,5,1}, {39,35}, {40,38,21,19}, {41,38}, {42,41,20,19}, {43,42,38,37}, {44,43,18,17}, {45,44,42,41}, {46,45,26,25}, {47,42}, {48,47,21,20}, {49,40}, {50,49,24,23}, {51,50,36,35}, {52,49}, {53,52,38,37}, {54,53,18,17}, {55,31}, {56,55,35,34}, {57,50}, {58,39}, {59,58,38,37}, {60,59}, {61,60,46,45}, {62,61,6,5}, {63,62}, }; //m is upperbound; things break if it isn't positive UniqueRandom(long m) { max = m; lfsr = seed; //could easily pass a starting point instead //figure out number of bits int bits = 0; long b = m; while((b >>>= 1) != 0) { bits++; } bits++; if(bits < 3) bits = 3; mask = 0; for(int i = 0; i < taps[bits].length; i++) { mask |= (1L << (taps[bits][i]-1)); } } //return -1 if we've cycled long next() { long ret = -1; if(lfsr == 0) return -1; do { ret = lfsr; //update lfsr - from wikipedia long lsb = lfsr & 1; lfsr >>>= 1; if(lsb == 1) lfsr ^= mask; if(lfsr == seed) lfsr = 0; //cycled, stick ret--; //zero is stuck state, never generated so sub 1 to get it } while(ret >= max); return ret; } 

}

Esta respuesta sugiere algunas estrategias para obtener lo que desea y asegurarse de que estén en orden aleatorio utilizando algunos algoritmos ya conocidos.

Existe una versión interna del algoritmo aleatorio Fisher-Yates, llamado la versión Durstenfeld, que distribuye aleatoriamente elementos adquiridos secuencialmente en matrices y colecciones al cargar la matriz o colección.

Una cosa para recordar es que la mezcla aleatoria de Fisher-Yates (AKA Knuth) o la versión de Durstenfeld utilizada en el momento de carga es altamente eficiente con arreglos de objetos porque solo se mueve el puntero de referencia al objeto y el objeto en sí no tiene que ser examinado o comparado con cualquier otro objeto como parte del algoritmo.

Daré ambos algoritmos más adelante.

Si quieres números aleatorios realmente grandes, del orden de 1024 bytes o más, bastará un generador aleatorio realmente bueno que pueda generar bytes o palabras sin signo a la vez. Genere al azar tantos bytes o palabras como necesite para construir el número, conviértalo en un objeto con un puntero de referencia y, listo, tiene un entero aleatorio realmente enorme. Si necesita un rango específico realmente grande, puede agregar un valor base de cero bytes al final de orden bajo de la secuencia de bytes para subir el valor. Esta puede ser tu mejor opción.

Si necesita eliminar duplicados de números aleatorios realmente grandes, entonces eso es más complicado. Incluso con números aleatorios realmente grandes, eliminar duplicados también los hace significativamente sesgados y no aleatorios en absoluto. Si tiene un conjunto realmente grande de números aleatorios muy grandes no duplicados y selecciona al azar entre los que aún no se han seleccionado, entonces el sesgo es solo el sesgo en la creación de los valores enormes para el enorme conjunto de números entre los que puede elegir. Una versión inversa de la versión de Yates-Fisher de Durstenfeld podría usarse para elegir aleatoriamente los valores de un conjunto realmente grande de ellos, eliminarlos de los valores restantes para elegir e insertarlos en una nueva matriz que es un subconjunto y podría hacer esto solo con las matrices de origen y destino in situ. Esto sería muy eficiente.

Esta puede ser una buena estrategia para obtener un pequeño número de números aleatorios con valores enormes de un conjunto realmente grande en el que no están duplicados. Simplemente elija una ubicación aleatoria en el conjunto de origen, obtenga su valor, cambie su valor con el elemento superior en el conjunto de origen, reduzca el tamaño de la fuente en uno y repita con el conjunto de origen de tamaño reducido hasta que haya elegido suficientes valores. Esto es esencialmente la versión Durstenfeld de Fisher-Yates en reversa. A continuación, puede usar la versión de Dursenfeld del algoritmo de Fisher-Yates para insertar los valores adquiridos en el conjunto de destino. Sin embargo, eso es excesivo, ya que deben elegirse al azar y ordenarse aleatoriamente como se indica aquí.

Ambos algoritmos suponen que tiene algún método de instancia de número aleatorio, nextInt (int setSize), que genera un entero aleatorio de cero a setSize, lo que significa que hay valores posibles de setSize. En este caso, será el tamaño de la matriz, ya que el último índice de la matriz es tamaño-1.

El primer algoritmo es la versión de Durstenfeld del algoritmo aleatorio Fisher-Yates (también conocido como Knuth) aplicado a una matriz de longitud arbitraria, una que simplemente coloca aleatoriamente enteros desde 0 hasta la longitud de la matriz en la matriz. La matriz no necesita ser una matriz de enteros, sino que puede ser una matriz de cualquier objeto que se adquiere de forma secuencial, lo que, efectivamente, la convierte en una matriz de punteros de referencia. Es simple, corto y muy efectivo

 int size = someNumber; int[] int array = new int[size]; // here is the array to load int location; // this will get assigned a value before used // i will also conveniently be the value to load, but any sequentially acquired // object will work for (int i = 0; i <= size; i++) { // conveniently, i is also the value to load // you can instance or acquire any object at this place in the algorithm to load // by reference, into the array and use a pointer to it in place of j int j = i; // in this example, j is trivially i if (i == 0) { // first integer goes into first location array[i] = j; // this may get swapped from here later } else { // subsequent integers go into random locations // the next random location will be somewhere in the locations // already used or a new one at the end // here we get the next random location // to preserve true randomness without a significant bias // it is REALLY IMPORTANT that the newest value could be // stored in the newest location, that is, // location has to be able to randomly have the value i int location = nextInt(i + 1); // a random value between 0 and i // move the random location's value to the new location array[i] = array[location]; array[location] = j; // put the new value into the random location } // end if...else } // end for 

Voila, ahora tienes una matriz ya aleatorizada.

Si quiere barajar al azar una matriz que ya tiene, aquí está el algoritmo estándar de Fisher-Yates.

 type[] array = new type[size]; // some code that loads array... // randomly pick an item anywhere in the current array segment, // swap it with the top element in the current array segment, // then shorten the array segment by 1 // just as with the Durstenfeld version above, // it is REALLY IMPORTANT that an element could get // swapped with itself to avoid any bias in the randomization type temp; // this will get assigned a value before used int location; // this will get assigned a value before used for (int i = arrayLength -1 ; i > 0; i--) { int location = nextInt(i + 1); temp = array[i]; array[i] = array[location]; array[location] = temp; } // end for 

Para colecciones y conjuntos secuenciados, es decir, algún tipo de objeto de lista, puede usar complementos o inserciones con un valor de índice que le permite insertar elementos en cualquier lugar, pero debe permitir agregarlos o agregarlos después del último elemento actual para evitar crear sesgos. en la aleatorización.

Aquí hay un camino al azar sin repetir los resultados. También funciona para cadenas. Está en C # pero el logig debería funcionar en muchos lugares. Coloque los resultados aleatorios en una lista y verifique si el nuevo elemento aleatorio está en esa lista. Si no es así, tienes un nuevo elemento aleatorio. Si está en esa lista, repite el azar hasta que obtengas un elemento que no está en esa lista.

 List Erledigte = new List(); private void Form1_Load(object sender, EventArgs e) { label1.Text = ""; listBox1.Items.Add("a"); listBox1.Items.Add("b"); listBox1.Items.Add("c"); listBox1.Items.Add("d"); listBox1.Items.Add("e"); } private void button1_Click(object sender, EventArgs e) { Random rand = new Random(); int index=rand.Next(0, listBox1.Items.Count); string rndString = listBox1.Items[index].ToString(); if (listBox1.Items.Count <= Erledigte.Count) { return; } else { if (Erledigte.Contains(rndString)) { //MessageBox.Show("vorhanden"); while (Erledigte.Contains(rndString)) { index = rand.Next(0, listBox1.Items.Count); rndString = listBox1.Items[index].ToString(); } } Erledigte.Add(rndString); label1.Text += rndString; } } 

Para que una secuencia sea aleatoria, no debe haber ninguna autocorrelación. La restricción de que los números no se repitan significa que el siguiente número debería depender de todos los números anteriores, lo que significa que ya no es aleatorio ….

Si puede generar números aleatorios ‘pequeños’, puede generar números aleatorios ‘grandes’ integrándolos: agregue un pequeño incremento aleatorio a cada ‘anterior’.

 const size_t amount = 100; // a limited amount of random numbers vector numbers; numbers.reserve( amount ); const short int spread = 250; // about 250 between each random number numbers.push_back( myrandom( spread ) ); for( int n = 0; n != amount; ++n ) { const short int increment = myrandom( spread ); numbers.push_back( numbers.back() + increment ); } myshuffle( numbers ); 

Las funciones de myrandom y myshuffle esta medio generosamente delegar a otros 🙂

En realidad, hay un punto menor que hacer aquí; un generador de números aleatorios que no se permite repetir no es aleatorio.

tener números aleatorios no repetidos y evitar el tiempo de espera con la verificación de números de dobles y obtener números nuevos una y otra vez, utilice el siguiente método que asegurará el uso mínimo de Rand: por ejemplo, si quiere obtener 100 números aleatorios no repetidos: 1. llene una matriz con números del 1 al 100 2. obtenga un número aleatorio usando la función Rand en el rango de (1-100) 3. use el número aleatorio genarted como un índice para obtener el valor de la matriz (Números [IndexGeneratedFromRandFunction] 4 cambie el número en la matriz después de ese índice a la izquierda 5. repita desde el paso 2, pero ahora el sondeo debería ser (1-99) y continúe

ahora tenemos una matriz con diferentes números!

 int main() { int b[(the number if them)]; for (int i = 0; i < (the number of them); i++) { int a = rand() % (the number of them + 1) + 1; int j = 0; while (j < i) { if (a == b[j]) { a = rand() % (the number of them + 1) + 1; j = -1; } j++; } b[i] = a; } }