web-dev-qa-db-fra.com

Java générant des nombres aléatoires non répétitifs

Je veux créer un ensemble de nombres aléatoires sans doublons en Java.

Par exemple, j'ai un tableau pour stocker 10 000 entiers aléatoires de 0 à 9999.

Voici ce que j'ai jusqu'à présent:

import Java.util.Random;
public class Sort{

    public static void main(String[] args){

        int[] nums = new int[10000];

        Random randomGenerator = new Random();

        for (int i = 0; i < nums.length; ++i){
            nums[i] = randomGenerator.nextInt(10000);
        }
    }
}

Mais le code ci-dessus crée des doublons. Comment puis-je m'assurer que les nombres aléatoires ne se répètent pas?

29
Fernando Martinez
Integer[] arr = {...};
Collections.shuffle(Arrays.asList(arr));

Par exemple:

public static void main(String[] args) {
    Integer[] arr = new Integer[1000];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = i;
    }
    Collections.shuffle(Arrays.asList(arr));
    System.out.println(Arrays.toString(arr));

}
41
Achintya Jha

Un algorithme simple qui vous donne des nombres aléatoires sans doublons se trouve dans le livre Programming Pearls p. 127.

Attention: le tableau résultant contient les nombres dans l'ordre! Si vous les voulez dans un ordre aléatoire, vous devez mélanger le tableau, avec Fisher – Yates shuffle ou en utilisant une liste et appelez Collections.shuffle().

L'avantage de cet algorithme est qu'il n'est pas nécessaire de créer un tableau avec tous les nombres possibles et que la complexité de l'exécution est toujours linéaire O(n).

public static int[] sampleRandomNumbersWithoutRepetition(int start, int end, int count) {
    Random rng = new Random();

    int[] result = new int[count];
    int cur = 0;
    int remaining = end - start;
    for (int i = start; i < end && count > 0; i++) {
        double probability = rng.nextDouble();
        if (probability < ((double) count) / (double) remaining) {
            count--;
            result[cur++] = i;
        }
        remaining--;
    }
    return result;
}
7
the

Achintya Jha a la bonne idée ici. Au lieu de penser à la façon de supprimer les doublons, vous supprimez la possibilité de créer des doublons en premier lieu.

Si vous souhaitez vous en tenir à un tableau d’entités et si vous souhaitez randomiser leur ordre (manuellement, ce qui est assez simple), suivez ces étapes.

  1. créer un tableau de taille n.
  2. bouclez et initialisez chaque valeur d'indice i à la valeur i (ou i + 1 si vous souhaitez avoir les nombres de 1 à n plutôt que 0 à n-1).
  3. enfin, parcourez à nouveau le tableau en échangeant chaque valeur pour une valeur à un index aléatoire.

Votre code pourrait être modifié pour ressembler à ceci:

import Java.util.Random;

public class Sort
{
    // use a constant rather than having the "magic number" 10000 scattered about
    public static final int N = 10000;

    public static void main(String[] args)
    {
        //array to store N random integers (0 - N-1)
        int[] nums = new int[N];

        // initialize each value at index i to the value i 
        for (int i = 0; i < nums.length; ++i)
        {
            nums[i] = i;
        }

        Random randomGenerator = new Random();
        int randomIndex; // the randomly selected index each time through the loop
        int randomValue; // the value at nums[randomIndex] each time through the loop

        // randomize order of values
        for(int i = 0; i < nums.length; ++i)
        {
             // select a random index
             randomIndex = randomGenerator.nextInt(nums.length);

             // swap values
             randomValue = nums[randomIndex];
             nums[randomIndex] = nums[i];
             nums[i] = randomValue;
        }
    }
}

Et si j'étais vous, je diviserais probablement chacun de ces blocs en méthodes séparées et plus petites plutôt qu'en une seule méthode principale.

J'espère que cela t'aides.

3
Benjamin Brumfield

Si vous avez besoin de générer des nombres avec des intervalles, cela peut être comme ça:

Integer[] arr = new Integer[((int) (Math.random() * (16 - 30) + 30))];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
Collections.shuffle(Arrays.asList(arr));
System.out.println(Arrays.toString(arr));`

Le résultat:

[1, 10, 2, 4, 9, 8, 7, 13, 18, 17, 5, 21, 12, 16, 23, 20, 6, 0, 22, 14, 24, 15, 3, 11, 19]

Remarque: 

Si vous avez besoin que le zéro ne part pas, vous pouvez mettre un "si"

2
Marcus person

Que dis-tu de ça?

LinkedHashSet<Integer> test = new LinkedHashSet<Integer>();
Random random = new Random();
do{
    test.add(random.nextInt(1000) + 1);
}while(test.size() != 1000);

L'utilisateur peut ensuite parcourir la Set à l'aide d'une boucle for.

0
Jitin Kodian

En Java 8, si vous voulez avoir un list d'entiers aléatoires N non répétitifs dans range (a, b), où b est exclusif, vous pouvez utiliser quelque chose comme ceci:

Random random = new Random();
List<Integer> randomNumbers = random.ints(a, b).distinct().limit(N).boxed().collect(Collectors.toList());
0
Slawomir Domagala