Afin de s'assurer que la liste ne se répète pas, il faudrait conserver une liste des numéros précédemment retournés. Comme il doit donc générer la liste entière à la fin de l'algorithme, cela équivaut, en termes de besoins de stockage, à générer la liste ordonnée puis à la mélanger.
Pour en savoir plus sur le brassage, cliquez ici : http://stackoverflow.com/questions/168037/creating-a-random-ordered-list-from-an-ordered-list
Cependant, si la plage des nombres aléatoires est très large mais que la quantité de nombres requise est faible (vous avez laissé entendre que c'est la condition réelle dans un commentaire), alors générer une liste complète et la mélanger est un gaspillage. Le brassage d'un énorme tableau implique d'accéder à des pages de mémoire virtuelle d'une manière qui (par définition) mettra en échec le système de pagination du système d'exploitation (à plus petite échelle, le même problème se poserait avec le cache mémoire du CPU).
Dans ce cas, la recherche dans la liste jusqu'à présent sera beaucoup plus efficace. L'idéal serait donc d'utiliser une heuristique (déterminée par l'expérience) pour choisir la bonne implémentation pour les arguments donnés. (Je m'excuse de donner des exemples en C# plutôt qu'en C++ mais ASFAC++B Je m'entraîne à penser en C#).
IEnumerable<int> 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<int> used = new HashSet<int>();
for (int n = 0; n < quantity; n++)
{
int r = Random(range);
while (!used.Add(r))
r = Random(range);
a[n] = r;
}
}
return a;
}
Le coût de la vérification des nombres répétés, des boucles lorsqu'il y a des collisions, etc. sera élevé, mais il y aura probablement un certain nombre d'améliorations. Threshold
où cela devient plus rapide que d'allouer pour la plage entière.
Pour des besoins en quantité suffisamment faible, il peut être plus rapide d'utiliser un tableau pour used
et faire des recherches linéaires dans celui-ci, en raison de la plus grande localité, de la moindre surcharge, de l'économie de la comparaison...
De même, pour de grandes quantités ET de grandes plages, il peut être préférable de renvoyer un objet qui produit les numéros de la séquence sur demande, au lieu d'allouer d'emblée le tableau des résultats. Ceci est très facile à mettre en œuvre en C# grâce à la fonction yield return
mot-clé :
IEnumerable<int> 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;
}
}