Je voudrais générer des nombres aléatoires uniques entre 0 et 1000 qui ne se répètent jamais (c'est-à-dire que 6 ne s'affiche pas deux fois), mais cela ne recourt pas à quelque chose comme une recherche O (N) des valeurs précédentes pour le faire. Est-ce possible?
algorithm
math
random
language-agnostic
dicroce
la source
la source
O(n)
dans le temps ou la mémoire), alors la plupart des réponses ci-dessous sont fausses, y compris la réponse acceptée.Réponses:
Initialisez un tableau de 1001 entiers avec les valeurs 0-1000 et définissez une variable, max, sur l'indice max actuel du tableau (en commençant par 1000). Choisissez un nombre aléatoire, r, entre 0 et max, échangez le nombre à la position r avec le nombre à la position max et renvoyez le nombre maintenant à la position max. Décrémentez max de 1 et continuez. Lorsque max est égal à 0, redéfinissez max sur la taille du tableau - 1 et recommencez sans avoir besoin de réinitialiser le tableau.
Mise à jour: Bien que j'aie proposé cette méthode moi-même lorsque j'ai répondu à la question, après quelques recherches, je me rends compte qu'il s'agit d'une version modifiée de Fisher-Yates connue sous le nom de Durstenfeld-Fisher-Yates ou Knuth-Fisher-Yates. Puisque la description peut être un peu difficile à suivre, j'ai fourni un exemple ci-dessous (en utilisant 11 éléments au lieu de 1001):
Array commence avec 11 éléments initialisés à array [n] = n, max commence à 10:
A chaque itération, un nombre aléatoire r est sélectionné entre 0 et max, le tableau [r] et le tableau [max] sont permutés, le nouveau tableau [max] est renvoyé et max est décrémenté:
Après 11 itérations, tous les nombres du tableau ont été sélectionnés, max == 0, et les éléments du tableau sont mélangés:
À ce stade, max peut être réinitialisé à 10 et le processus peut se poursuivre.
la source
N
itérations (11 dans cet exemple) pour obtenir le résultat souhaité à chaque fois ne le signifierait-il pasO(n)
? Comme vous devez faire desN
itérations pour obtenir desN!
combinaisons à partir du même état initial, sinon votre sortie ne sera que l'un des N états.Tu peux le faire:
Cela ne nécessite donc pas une recherche des anciennes valeurs à chaque fois, mais cela nécessite toujours O (N) pour le mélange initial. Mais comme Nils l'a souligné dans ses commentaires, il s'agit d'un amortissement O (1).
la source
Utilisez un registre de décalage de rétroaction linéaire maximal .
Il est implémentable en quelques lignes de C et au moment de l'exécution, il ne fait guère plus que quelques tests / branches, un petit ajout et un changement de bits. Ce n'est pas aléatoire, mais cela trompe la plupart des gens.
la source
Vous pouvez utiliser un générateur congruentiel linéaire . Où
m
(le module) serait le nombre premier le plus proche supérieur à 1000. Lorsque vous obtenez un nombre hors de la plage, obtenez simplement le suivant. La séquence ne se répétera qu'une fois que tous les éléments se sont produits et vous n'avez pas à utiliser de tableau. Soyez conscient des inconvénients de ce générateur (y compris le manque de caractère aléatoire).la source
k
uns des autres dans la séquence ne peuvent jamais se produire ensemble).Vous pouvez utiliser le cryptage avec préservation du format pour crypter un compteur. Votre compteur va juste de 0 et le cryptage utilise une clé de votre choix pour le transformer en une valeur apparemment aléatoire de la base et de la largeur souhaitées. Par exemple, pour l'exemple de cette question: base 10, largeur 3.
Les chiffrements par blocs ont normalement une taille de bloc fixe de, par exemple, 64 ou 128 bits. Mais le cryptage avec préservation du format vous permet de prendre un chiffrement standard comme AES et de créer un chiffrement de plus petite largeur, de la base et de la largeur que vous souhaitez, avec un algorithme qui est toujours cryptographiquement robuste.
Il est garanti de ne jamais avoir de collisions (car les algorithmes cryptographiques créent un mappage 1: 1). Il est également réversible (un mappage bidirectionnel), vous pouvez donc prendre le nombre résultant et revenir à la valeur de compteur avec laquelle vous avez commencé.
Cette technique n'a pas besoin de mémoire pour stocker un tableau mélangé, etc., ce qui peut être un avantage sur les systèmes avec une mémoire limitée.
AES-FFX est une méthode standard proposée pour y parvenir. J'ai expérimenté du code Python de base basé sur l'idée AES-FFX, bien que pas totalement conforme - voir le code Python ici . Il peut par exemple crypter un compteur sur un nombre décimal à 7 chiffres à la recherche aléatoire ou un nombre de 16 bits. Voici un exemple de base 10, largeur 3 (pour donner un nombre compris entre 0 et 999 inclus) comme la question posée:
Pour obtenir différentes séquences pseudo-aléatoires non répétitives, modifiez la clé de chiffrement. Chaque clé de chiffrement produit une séquence pseudo-aléatoire non répétitive différente.
la source
k
séparées dans la séquence ne peuvent jamais se produire ensemble).k
?1,2,...,N
par une séquence des mêmes nombres dans un autre ordre, mais toujours constant. Les nombres sont ensuite extraits de cette séquence un par un.k
est le nombre de valeurs choisies (l'OP n'a pas spécifié de lettre, j'ai donc dû en introduire une).Pour les nombres faibles comme 0 ... 1000, créer une liste contenant tous les nombres et la mélanger est simple. Mais si l'ensemble de nombres à partir duquel tirer est très grand, il existe un autre moyen élégant: vous pouvez construire une permutation pseudo-aléatoire en utilisant une clé et une fonction de hachage cryptographique. Consultez l'exemple de pseudo-code C ++ suivant:
Voici
hash
juste une fonction pseudo-aléatoire arbitraire qui mappe une chaîne de caractères à un entier non signé éventuellement énorme. La fonctionrandperm
est une permutation de tous les nombres entre 0 ... pow (2, bits) -1 en supposant une clé fixe. Cela découle de la construction car chaque étape qui modifie la variableindex
est réversible. Ceci est inspiré d'un chiffrement Feistel .la source
hash()
, telle qu'utilisée dans le code ci-dessus, est une fonction pseudo-aléatoire sécurisée, cette construction produira de manière prouvée (Luby & Rackoff, 1988) une permutation pseudo - aléatoire , qui ne peut être distinguée d'un véritable mélange aléatoire utilisant beaucoup moins d'effort qu'un recherche de l'espace clé entier, qui est exponentiel dans la longueur de clé. Même pour des clés de taille raisonnable (par exemple, 128 bits), cela dépasse la puissance de calcul totale disponible sur Terre.hash( key + "/" + int2str(temp) )
construction ad hoc ci-dessus par HMAC , dont la sécurité peut à son tour être réduite à celle de la fonction de compression de hachage sous-jacente. De plus, l'utilisation de HMAC peut rendre il est moins probable que quelqu'un essaie par erreur d'utiliser cette construction avec une fonction de hachage non cryptée non sécurisée.)Vous pouvez utiliser mon algorithme Xincrol décrit ici:
http://openpatent.blogspot.co.il/2013/04/xincrol-unique-and-random-number.html
Il s'agit d'une méthode algorithmique pure de génération de nombres aléatoires mais uniques sans tableaux, listes, permutations ou charge CPU lourde.
La dernière version permet également de définir la plage de nombres, par exemple, si je veux des nombres aléatoires uniques dans la plage de 0-1073741821.
Je l'ai pratiquement utilisé pour
C'est ouvert, gratuit. Essaie...
la source
k
séparées dans la séquence ne peuvent jamais se produire ensemble).Vous n'avez même pas besoin d'un tableau pour résoudre celui-ci.
Vous avez besoin d'un bitmask et d'un compteur.
Initialisez le compteur à zéro et incrémentez-le lors des appels successifs. XOR le compteur avec le masque de bits (sélectionné au hasard au démarrage, ou fixe) pour générer un nombre pseudo-aléatoire. Si vous ne pouvez pas avoir de nombres supérieurs à 1000, n'utilisez pas de masque de bits plus large que 9 bits. (En d'autres termes, le masque de bits est un entier non supérieur à 511.)
Assurez-vous que lorsque le compteur dépasse 1000, vous le remettez à zéro. À ce stade, vous pouvez sélectionner un autre masque de bits aléatoire - si vous le souhaitez - pour produire le même ensemble de nombres dans un ordre différent.
la source
Je pense que le générateur congruentiel linéaire serait la solution la plus simple.
et il n'y a que trois restrictions à l' un , c et m valeurs
PS, la méthode a déjà été mentionnée mais le message a de fausses hypothèses sur les valeurs constantes. Les constantes ci-dessous devraient fonctionner correctement pour votre cas
Dans votre cas , vous pouvez utiliser
a = 1002
,c = 757
,m = 1001
la source
Voici un code que j'ai tapé qui utilise la logique de la première solution. Je sais que c'est "indépendant du langage", mais je voulais juste présenter cela comme un exemple en C # au cas où quelqu'un chercherait une solution pratique rapide.
la source
Cette méthode est appropriée lorsque la limite est élevée et que vous ne souhaitez générer que quelques nombres aléatoires.
Notez que les nombres sont générés par ordre croissant, mais vous pouvez ensuite les mélanger ensuite.
la source
(top,n)=(100,10)
sont:(0.01047705, 0.01044825, 0.01041225, ..., 0.0088324, 0.008723, 0.00863635)
. J'ai testé en Python, donc de légères différences en mathématiques pourraient jouer un rôle ici (je me suis assuré que toutes les opérations de calculr
sont en virgule flottante).Vous pouvez utiliser un bon générateur de nombres pseudo-aléatoires avec 10 bits et jeter 1001 à 1023 en laissant 0 à 1000.
De là, nous obtenons la conception d'un PRNG 10 bits.
10 bits, polynôme de rétroaction x ^ 10 + x ^ 7 + 1 (période 1023)
utiliser un LFSR Galois pour obtenir du code rapide
la source
N Les nombres aléatoires non répétitifs seront de complexité O (n), selon les besoins.
Remarque: Aléatoire doit être statique avec la sécurité des fils appliquée.
la source
Supposons que vous souhaitiez parcourir les listes mélangées encore et encore, sans avoir le
O(n)
délai chaque fois que vous recommencez pour les mélanger à nouveau, dans ce cas, nous pouvons le faire:Créer 2 listes A et B, de 0 à 1000, prend de la
2n
place.Mélanger la liste A à l'aide de Fisher-Yates, prend du
n
temps.Lorsque vous dessinez un nombre, effectuez un mélange Fisher-Yates en une étape sur l'autre liste.
Lorsque le curseur est à la fin de la liste, passez à l'autre liste.
Prétraiter
Dessiner
la source
[1,3,4,5,2]
produira le même résultat que la lecture aléatoire[1,2,3,4,5]
.La question Comment générer efficacement une liste de K entiers non répétitifs entre 0 et une borne supérieure N est liée comme un doublon - et si vous voulez quelque chose qui est O (1) par nombre aléatoire généré (sans O (n) coût de démarrage)) il y a une simple modification de la réponse acceptée.
Créez une carte vide non ordonnée (une carte ordonnée vide prendra O (log k) par élément) d'un entier à un entier - au lieu d'utiliser un tableau initialisé. Définissez max à 1000 si c'est le maximum,
La seule différence par rapport à l'utilisation d'un tableau initialisé est que l'initialisation des éléments est reportée / ignorée - mais elle générera exactement les mêmes nombres à partir du même PRNG.
la source
Une autre posibilité:
Vous pouvez utiliser un tableau d'indicateurs. Et prenez le suivant quand il est déjà choisi.
Mais attention après 1000 appels, la fonction ne se terminera jamais donc vous devez faire une sauvegarde.
la source
Voici un exemple de code COBOL avec lequel vous pouvez jouer.
Je peux vous envoyer un fichier RANDGEN.exe afin que vous puissiez jouer avec pour voir s'il veut que vous le vouliez.
la source
La plupart des réponses ici ne garantissent pas qu'elles ne renverront pas le même numéro deux fois. Voici une solution correcte:
Je ne suis pas sûr que la contrainte soit bien spécifiée. On suppose qu'après 1000 autres sorties, une valeur est autorisée à se répéter, mais cela permet naïvement à 0 de suivre immédiatement après 0 tant qu'ils apparaissent tous les deux à la fin et au début des ensembles de 1000. Inversement, s'il est possible de garder une distance de 1000 autres valeurs entre les répétitions, ce qui force une situation où la séquence se rejoue exactement de la même manière à chaque fois car aucune autre valeur ne s'est produite en dehors de cette limite.
Voici une méthode qui garantit toujours au moins 500 autres valeurs avant qu'une valeur puisse être répétée:
la source
Lorsque N est supérieur à 1000 et que vous devez tirer K échantillons aléatoires, vous pouvez utiliser un ensemble contenant les échantillons jusqu'à présent. Pour chaque tirage, vous utilisez un échantillonnage de rejet , qui sera une opération "presque" O (1), de sorte que la durée totale de fonctionnement est proche de O (K) avec un stockage O (N).
Cet algorithme se heurte lorsque K est "proche" de N. Cela signifie que le temps d'exécution sera bien pire que O (K). Une solution simple consiste à inverser la logique de sorte que, pour K> N / 2, vous gardiez un enregistrement de tous les échantillons qui n'ont pas encore été tirés. Chaque tirage supprime un échantillon de l'ensemble de rejet.
L'autre problème évident avec l'échantillonnage de rejet est qu'il s'agit du stockage O (N), ce qui est une mauvaise nouvelle si N est dans les milliards ou plus. Cependant, il existe un algorithme qui résout ce problème. Cet algorithme est appelé l'algorithme de Vitter après son inventeur. L'algorithme est décrit ici . L'essentiel de l'algorithme de Vitter est qu'après chaque tirage, vous calculez un saut aléatoire en utilisant une certaine distribution qui garantit un échantillonnage uniforme.
la source
Fisher Yates
C'est en fait O (n-1) car vous n'avez besoin que d'un swap pour les deux derniers
C'est C #
la source
Veuillez consulter ma réponse sur https://stackoverflow.com/a/46807110/8794687
C'est l'un des algorithmes les plus simples qui ont une complexité temporelle moyenne O ( s log s ), s indiquant la taille de l'échantillon. Il existe également des liens vers des algorithmes de table de hachage dont la complexité est supposée être O ( s ).
la source
Quelqu'un a posté "la création de nombres aléatoires dans Excel". J'utilise cet idéal. Créez une structure en 2 parties, str.index et str.ran; Pour 10 nombres aléatoires, créez un tableau de 10 structures. Définissez str.index de 0 à 9 et str.ran sur un nombre aléatoire différent.
Triez le tableau sur les valeurs de arr [i] .ran. Le str.index est maintenant dans un ordre aléatoire. Ci-dessous le code c:
la source