La création de nombres aléatoires avec pas de doublons
Dans ce cas, le MAX n'est que de 5, donc j'ai pu vérifier les doublons, un par un, mais comment pourrais-je le faire de façon plus simple? Par exemple, si le MAX est équipé d'une valeur de 20?
Merci.
int MAX = 5;
for (i = 1 , i <= MAX; i++)
{
drawNum[1] = (int)(Math.random()*MAX)+1;
while (drawNum[2] == drawNum[1])
{
drawNum[2] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
{
drawNum[3] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
{
drawNum[4] = (int)(Math.random()*MAX)+1;
}
while ((drawNum[5] == drawNum[1]) ||
(drawNum[5] == drawNum[2]) ||
(drawNum[5] == drawNum[3]) ||
(drawNum[5] == drawNum[4]) )
{
drawNum[5] = (int)(Math.random()*MAX)+1;
}
}
- Beaucoup de (pseudo) des générateurs de nombres aléatoires ne le répétez pas pour leur "cycle". Le problème est, bien sûr, que l'ensemble de leur "cycle" est des milliards ou des milliers de milliards de valeurs, et les valeurs qu'ils produisent peuvent être l'un de ceux des milliards ou des milliers de milliards de valeurs. Vous pourriez en théorie de produire un générateur de nombre aléatoire qui a eu un "cycle" de 5 ou 10 ou que ce soit, mais il est probablement le plus d'ennuis que cela vaut la peine.
- Également un générateur de nombre aléatoire qui permet de ne pas répéter ce qui est encore "moins" aléatoire: si MAX=5 et que vous lisez les 3 numéros, vous pouvez deviner le prochain avec une probabilité de 50%, si vous lisez 4 numéros, vous savez la prochaine pour sûr à 100%!
- Répondu sur un double de la question ici
- Voir aussi Génération de Nombres Aléatoires en Java
- Double Possible de Comment avez-vous efficacement pour générer une liste de K de non-répétition des entiers compris entre 0 et une limite supérieure N
Vous devez vous connecter pour publier un commentaire.
La façon la plus simple serait de créer une liste de nombres (1..20 ou quoi que ce soit), puis les mélanger avec
Collections.shuffle
. Puis il suffit de prendre toutefois de nombreux éléments que vous voulez. C'est très bien si votre portée est égale au nombre d'éléments dont vous avez besoin à la fin (par exemple, pour traînant un jeu de cartes).Qui ne fonctionne pas tellement bien si vous voulez (par exemple) 10 éléments aléatoires dans l'intervalle 1..10,000 - vous finirais par faire beaucoup de travail inutilement. À ce stade, il est probablement préférable de garder un ensemble de valeurs que vous avez généré jusqu'à présent, et juste continuer à générer des nombres dans une boucle jusqu'à ce que le prochain n'est pas déjà présent:
Être prudent avec le choix même si j'ai très délibérément utilisé
LinkedHashSet
car il maintient l'ordre d'insertion, ce qui nous intéresse ici, c'.Encore une autre option est de toujours faire des progrès, par la réduction de la gamme de chaque temps et de compensation pour les valeurs existantes. Ainsi, par exemple, supposons que vous vouliez 3 valeurs dans l'intervalle 0..9. Sur la première itération, vous auriez générer un nombre dans l'intervalle 0..9 - disons que vous générez un 4.
Sur la deuxième itération vous pouvez générer un nombre dans l'intervalle 0..8. Si le nombre généré est inférieur à 4, vous garderais comme ça... sinon, vous ajoutez une. Qui vous obtient un résultat de 0..9 sans 4. Supposons que nous obtenons 7 de cette façon.
Sur la troisième itération, vous auriez générer un nombre dans l'intervalle 0..7. Si le nombre généré est inférieur à 4, vous auriez du garder comme ça. Si c'est 4 ou 5, vous devez ajouter un. Si c'est 6 ou 7, vous devez ajouter deux. De cette façon, le résultat varie de 0..9 sans 4 ou 6.
ẁhile (generated.size() < numbersNeeded)
, que je trouve plus propreSet
approche de supprimer les doublons, veuillez jeter un oeil à ma question:stackoverflow.com/questions/31776161/...TreeSet
, donc est-ce que vous ajoutez des choses, ils viennent dans l'ordre croissant. De quelle manière est que hasard? C'est juste un exemple extrême, mais d'autres collections peut permettre (dire) le code de hachage d'affecter la commande, en faisant des rangements impossible, ou même un peu moins susceptible de se produire que les autres.Voici comment je le ferais
Que l'honorable M. Skeet a souligné:
Si n est le nombre de sélectionnés au hasard les numéros que vous souhaitez choisir et N est le total de l'échantillon de l'espace des numéros disponibles pour la sélection:
Une autre approche qui permet de spécifier le nombre de numéros que vous voulez avec
size
et lamin
etmax
valeurs de retour de numéros deUtiliser le retour 7 nombres entre 0 et 25.
Il y a une autre façon de faire "aléatoire" ordonné des nombres avec LFSR, jetez un oeil à:
http://en.wikipedia.org/wiki/Linear_feedback_shift_register
avec cette technique, vous pouvez obtenir l'ordonnée de nombres aléatoires par index et faire en sorte que les valeurs ne sont pas dupliqués.
Mais ce ne sont pas de VRAIS nombres aléatoires, parce que la génération aléatoire est déterministe.
Mais en fonction de votre cas vous pouvez utiliser cette technique réduisant la quantité de traitement sur la génération de nombre aléatoire lors de l'utilisation de brassage.
Ici un LFSR de l'algorithme en java, (je l'ai pris quelque part je n'ai pas l'oublier):
Le plus efficace, la méthode de base pour avoir de non-répétition des nombres aléatoires est expliqué par ce pseudo-code. Il n'est pas nécessaire d'avoir des boucles imbriquées ou haché recherches:
Supposons que la première itération aléatoires générés par le numéro 3 pour commencer (à partir de 0 - 19). Ce serait rendre les résultats[0] = cartographie[3], c'est à dire, la valeur 3. Nous avions ensuite affecter la cartographie[3] à 19.
Dans la prochaine itération, le nombre aléatoire est de 5 (de 0 à 18 ans). Ce serait rendre les résultats[1] = cartographie[5], c'est à dire, la valeur 5. Nous avions ensuite affecter la cartographie[5] à 18 ans.
Supposons maintenant que la prochaine itération choisi 3 nouveau (à partir de 0 - 17). les résultats de[2] serait affectée la valeur de la cartographie[3], mais maintenant, cette valeur n'est pas 3, mais 19.
De cette même protection persiste pour tous les numéros, même si vous avez le même nombre de 5 fois dans une rangée. E. g., si le générateur de nombre aléatoire vous a donné 0 cinq fois de suite, les résultats seraient: [ 0, 19, 18, 17, 16 ].
Vous ne jamais obtenir le même nombre deux fois.
De générer tous les indices d'une séquence est généralement une mauvaise idée, car cela peut prendre beaucoup de temps, surtout si le rapport entre le nombre d'être choisis pour
MAX
est faible (la complexité devient dominé parO(MAX)
). Cela devient pire si le rapport entre le nombre d'être choisis pourMAX
approches, comme le retrait d'choisi indices à partir de la séquence de tous les devient aussi cher (nous avons une approcheO(MAX^2/2)
). Mais pour les petits nombres, ce qui en général fonctionne bien et n'est pas particulièrement enclin à l'erreur.De filtrage de l'généré indices en utilisant une collection, c'est aussi une mauvaise idée, car peu de temps est consacré à l'insertion de l'index dans la séquence, et le progrès n'est pas garanti que le même nombre aléatoire peut être tirée en plusieurs fois (mais assez grande pour
MAX
c'est peu probable). Cela pourrait être proche de la complexitéO(k n log^2(n)/2)
, en ignorant les doublons et en supposant que la collection utilise un arbre pour faciliter la recherche (mais avec un important coût constantk
de l'allocation de l'arbre de nœuds, et après avoir éventuellement à rééquilibrer).Une autre option est de générer des valeurs aléatoires de manière unique à partir du début, en garantissant des progrès sont réalisés. Cela signifie que dans le premier tour, un hasard index dans
[0, MAX]
est généré:Dans le deuxième tour, seulement
[0, MAX - 1]
est généré (comme un seul élément est sélectionné):Les valeurs des indices doivent ensuite être ajusté: si l'index du deuxième tombe dans la seconde moitié de la séquence (après le premier index), il doit être augmenté pour tenir compte de l'écart. Nous pouvons mettre en œuvre la présente comme une boucle, ce qui nous permet de sélectionner nombre arbitraire d'objets uniques.
Pour de courtes séquences, c'est assez rapide
O(n^2/2)
algorithme:Où
n_select_num
est votre 5 etn_number_num
est votreMAX
. Len_Rand(x)
retourne entiers aléatoires dans[0, x]
(inclus). Cela peut être fait en un peu plus rapide si la sélection d'un grand nombre d'éléments (par exemple, pas 5, mais 500) à l'aide de binaires de recherche pour trouver le point d'insertion. Pour ce faire, nous devons nous assurer que nous remplissons les exigences.Nous ferons de recherche binaire avec la comparaison
n + j < rand_num[j]
qui est le même quen < rand_num[j] - j
. Nous avons besoin de montrer querand_num[j] - j
est encore une séquence ordonnée pour une séquence triéerand_num[j]
. C'est heureusement facilement montré, comme étant la plus petite distance entre deux éléments de l'originalrand_num
est l'un (les nombres générés sont uniques, il y a toujours une différence d'au moins 1). En même temps, si on soustrait les indicesj
de tous les élémentsrand_num[j]
, les différences dans l'indice sont exactement 1. Ainsi, dans le "pire" des cas, nous obtenons une constante de la séquence, mais jamais à la baisse. Le binaire de recherche peut donc être utilisé, produisantO(n log(n))
algorithme:Et enfin:
J'ai testé cela sur trois repères. Tout d'abord, les 3 numéros ont été choisis de 7 éléments, et un histogramme des éléments choisis a accumulé plus de 10 000 pistes:
Cela montre que chacun des 7 éléments a été choisi à peu près le même nombre de fois, et il n'est pas évident biais causé par l'algorithme. Toutes les séquences ont été également vérifié l'exactitude de l' (unicité de contenu).
Le deuxième point de référence consistait à choisir 7 numéros de 5000 articles. Le temps de plusieurs versions de l'algorithme a été accumulé plus de 10 000 000 pistes. Les résultats sont indiqués dans les commentaires dans le code
b1
. La version simple de l'algorithme est un peu plus rapide.Le troisième test consistait à choisir 700 numéros de 5000 articles. Le temps de plusieurs versions de l'algorithme a été créée, cette fois, plus de 10 000 pistes. Les résultats sont indiqués dans les commentaires dans le code
b2
. La recherche binaire version de l'algorithme est maintenant plus que deux fois plus rapide que la simple.La deuxième méthode commence à être plus rapide pour le choix plus que la dpa 75 articles sur ma machine (à noter que la complexité de l'algorithme ne dépend pas du nombre d'éléments,
MAX
).Il est à noter que les algorithmes ci-dessus générer des nombres aléatoires dans l'ordre croissant. Mais il serait simple d'ajouter un autre tableau dont les chiffres seront enregistrées dans l'ordre dans lequel ils ont été générés, et de retour à la place (à négligeable des coûts supplémentaires
O(n)
). Il n'est pas nécessaire de mélanger la sortie: ce serait beaucoup plus lent.Noter que les sources sont en C++, je n'ai pas de Java sur ma machine, mais le concept doit être clair.
MODIFIER:
Pour l'amusement, j'ai également mis en œuvre l'approche qui génère une liste avec tous les indices
0 .. MAX
, choisit au hasard et les supprime de la liste pour garantir l'unicité. Depuis que j'ai choisi assez élevéMAX
(5000), le rendement est catastrophique:J'ai également mis en œuvre l'approche avec un
set
(C++ collection), ce qui en fait vient en seconde place sur le benchmarkb2
, étant seulement environ 50% plus lent que l'approche avec le binaire de recherche. C'est compréhensible, que leset
utilise un arbre binaire, où le coût d'insertion est similaire à la recherche binaire. La seule différence est la possibilité d'obtenir des articles en double, ce qui ralentit la progression.L'intégralité du code source est ici.
Vous pouvez utiliser l'une des classes qui implémentent l'interface (API), puis chaque numéro de générer, utiliser.add() pour l'insérer.
Si la valeur de retour est faux, vous le savez, le nombre a déjà été produites avant.
Plutôt que de faire tout cela créer un
LinkedHashSet
objet et de nombres aléatoires parMath.random()
fonction .... si aucune entrée dupliquée se produit leLinkedHashSet
objet de ne pas ajouter ce numéro à la Liste ... Car dans cette Collection, la Classe pas de doublons sont autorisés .. en fin de compte u obtenir une liste de nombres aléatoires ayant pas de valeurs dupliquées .... 😀Votre problème semble se réduire à choisir k éléments au hasard à partir d'une collection de n éléments. Les Collections.shuffle réponse est donc correct, mais comme l'a souligné inefficace: ses O(n).
Wikipédia: shuffle de Fisher–Yates a un O(k) version lorsque le tableau existe déjà. Dans votre cas, il n'y a pas de tableau d'éléments et la création de la matrice d'éléments pourraient être très cher, de dire si max ont 10000000 au lieu de 20.
La lecture aléatoire de l'algorithme consiste à initialiser un tableau de taille n, où chaque élément est égal à son index, la cueillette de k nombres aléatoires chaque numéro dans une série avec le max un de moins que la gamme précédente, puis échange des éléments vers la fin du tableau.
Vous pouvez faire la même opération en O(k) temps avec une hashmap même si j'avoue que c'est une sorte de douleur. Notez que ce n'est utile que si k est de beaucoup inférieur à n. (c'est à dire k ~ lg(n) ou de faire), sinon, vous devez utiliser le shuffle directement.
Vous permettra d'utiliser votre table de hachage comme une représentation efficace de la sauvegarde de tableau dans la lecture aléatoire de l'algorithme. Tout élément de la matrice est égale à celle de l'indice n'a pas besoin d'apparaître dans la carte. Cela permet de représenter un tableau de taille n en temps constant, il n'y a pas de temps passé à l'initialisation.
Choisir k de nombres aléatoires: la première est dans la plage de 0 à n-1, la deuxième de 0 à n-2, le troisième de 0 à n-3 et ainsi de suite, thru n-k.
Traiter vos nombres aléatoires comme un ensemble de swaps. La première aléatoire des swaps indiciels à la position finale. La deuxième aléatoire des swaps indiciels à la seconde à la dernière position. Cependant, au lieu de travailler contre un support de tableau, travailler contre votre table de hachage. Votre table de hachage va stocker tout ce qui est hors de position.
creating the array of elements could be very expensive
-- pourquoi créer un tableau à être plus cher que le brassage? Je pense qu'il n'y a absolument aucune raison d'être pessimiste à ce point 🙂Ce serait beaucoup plus simple dans
java-8
:Il est l'algorithme de la carte de lot: vous créez un ensemble ordonné de nombres (la "carte de lot") et à chaque itération, vous sélectionnez un numéro au hasard position de (la suppression de la numéro sélectionné de la carte "lot", bien entendu).
Ici est une solution efficace pour la création rapide d'un essai randomisé de tableau. Après randomisation, vous pouvez simplement choisir le
n
-ème élémente
de la matrice, incrémentn
et retoure
. Cette solution a O(1) pour obtenir un nombre aléatoire et O(n) pour l'initialisation, mais comme un compromis nécessite une bonne quantité de mémoire si n devient assez grand.Il est plus efficace et moins encombrant solution pour les entiers de Collections.shuffle.
Le problème est le même que successivement choisir des éléments à partir de seulement l'onu-articles ramassés dans un ensemble et de les placer dans l'ordre quelque part d'autre. C'est exactement comme au hasard traitement des cartes de dessin ou de gagner des billets de tombola à partir d'un chapeau ou un bac.
Cet algorithme fonctionne pour le chargement de n'importe quel ensemble et de parvenir à un ordre aléatoire à la fin de la charge. Il travaille également pour l'ajout dans une Liste de la collection (ou tout autre indexé de la collection) et la réalisation d'une séquence aléatoire dans la collection à la fin de l'ajoute.
Il peut être fait avec un tableau unique, créé à la fois, ou numériquement commandé collectio, comme une Liste, à la place. Pour un tableau, la première la taille du tableau doit être de la taille exacte pour contenir tout ce qui est prévu valeurs. Si vous ne savez pas combien de valeurs peut se produire à l'avance, à l'aide d'un numériquement orderred collection, comme une liste de tableaux ou d'une Liste, où la taille n'est pas immuable, fonctionnera également. Il fonctionnera de façon universelle pour un tableau de n'importe quelle taille jusqu'à l'Entier.MAX_VALUE qui est un peu plus 2,000,000,000. Liste des objets ont le même indice de limites. Votre machine peut exécuter de mémoire avant d'arriver à un tableau de cette taille. Il peut être plus efficace pour charger un tableau typé pour les types d'objet et de le convertir à certains de collecte, d'après le chargement de la matrice. Cela est particulièrement vrai si l'objectif de collecte n'est pas indexé numériquement.
Cet algorithme, exactement comme c'est écrit, permettra de créer une distribution très homogène où il n'y a pas de doublons. Un aspect qui est TRÈS IMPORTANT, c'est qu'il doit être possible pour l'insertion de l'élément suivant à se produire jusqu'à la taille + 1. Ainsi, pour le deuxième point, il pourrait être possible de stocker dans la position 0 ou 1. Pour la 20e point, il pourrait être possible de les stocker dans n'importe quel endroit, de 0 à 19. Il est tout aussi possible que le premier élément de rester dans la position 0 comme il est pour elle à la fin jusqu'à un autre emplacement. Il est tout aussi possible que le prochain nouvel élément à aller n'importe où, y compris à la prochaine nouvel emplacement.
Le caractère aléatoire de la séquence va être aussi aléatoire que le caractère aléatoire du générateur de nombre aléatoire.
Cet algorithme peut aussi être utilisé pour charger les types de référence dans des endroits aléatoires dans un tableau. Puisque cela fonctionne avec un tableau, il peut également fonctionner avec des collections. Cela signifie que vous n'avez pas à créer la collection et puis se déplacer ou qui l'ont commandé sur ce que les commandes les objets en cours d'insertion. La collection ont besoin d'avoir la possibilité d'insérer un élément n'importe où dans la collection ou de l'ajouter.
Elle a vraiment tout dépend exactement CE que vous avez besoin de la génération aléatoire, mais voici mon point de vue.
Tout d'abord, créez un autonome méthode pour générer le nombre aléatoire.
Assurez-vous de permettre à des limites.
Ensuite, vous voulez pour créer une très simple structure de décision qui compare les valeurs. Cela peut être fait de deux façons. Si vous avez une quantité très limitée de numéros de vérifier, d'une SI simple déclaration suffira:
Ci-dessus compare int1 à int2 par int5, ainsi que de s'assurer qu'il n'y a pas de zéros dans les randoms.
Avec ces deux méthodes, nous pouvons effectuer les opérations suivantes:
Suivie Par:
Si vous avez une longue liste pour vérifier, puis une méthode plus complexe d'obtenir de meilleurs résultats à la fois dans la clarté du code et des ressources de traitement.
Espère que cette aide. Ce site m'a beaucoup aidée, je me suis senti obligé pour au moins ESSAYER de nous aider.
Code suivant permet de créer une séquence de nombre aléatoire entre [1,m] qui n'a pas été généré avant.