Я пытаюсь создать массив случайных чисел. Каждая запись массива будет иметь число от 0 до 31. Я пытаюсь получить код для генерации случайного числа, а затем проверить, существует ли это число в массиве. Если да, то он генерирует новое случайное число и снова проверяет с начала.
Я подумал, что я понял это с помощью кода ниже:
public class HelloWorld{
public static void main(String []args){
int[] randArray = new int[10];
boolean firstNumber = true;
int randNum = 0;
for (int j=0; j < randArray.length; j++) {
if(firstNumber) {
randNum = (int)(Math.random() * 31 + 1);
randArray[j] = randNum;
firstNumber = false;
} else {
for (int k=0; k < randArray.length;) {
randNum = (int)(Math.random() * 31 + 1);
if(randArray[k] == randNum) {
k=0;
} else {
k++;
}
}
randArray[j] = randNum;
System.out.println(j);
}
}
System.out.println("-------");
for(int i=0; i < randArray.length; i++) {
System.out.println(randArray[i]);
}
}
}
Но это то, что он печатает:
1 2 3 4 5 6 7 8 9 ------- 25 17 19 20 24 4 26 30 6 24
Как вы можете видеть, 24 повторяется дважды. Если я снова запустил код, вы можете увидеть повторяющиеся числа, которые повторяются.
По логике я не могу понять, почему это делается. Это может быть что-то простое, но я просто не вижу этого.
Я новичок в программировании, и это то, о чем я думал, что смогу проверить свои знания.
Вы можете попробовать этот код:
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
while (set.size() < 10) set.add((int)(Math.random() * 31) + 1);
Integer[] randArray = set.toArray(new Integer[0]);
for (int i = 0; i < randArray.length; i++) {
System.out.print(randArray[i] + " ");
}
System.out.println();
}
ПРИМЕР ВЫХОДА:
2 3 4 21 6 7 10 29 12 14
Ваш подход к генерации уникальных случайных чисел неверен, потому что, когда вы добираетесь до последнего числа n в своем массиве, у вас есть только 1/n шанс создать тот конкретный номер, который вам нужен. И поскольку вы работаете со случайными числами, может случиться так, что вы можете долго ждать, прежде чем успешно сгенерировать весь массив. Кроме того, время генерации массива дико непредсказуемо.
Гораздо лучший способ сделать это - создать массив с возрастающей последовательностью и перетасовать этот массив. Таким образом, вы гарантированно сгенерируете массив в O (n) и перетасовываете массив в O (n).
int arraySize=32;
int[] myArray= new int(arraySize);
for(int i=0;i<arraySize;i++) {
myArray[i]=i;
}
for(int i=0;i<arraySize;i++) {
int randNum = (int)(Math.random() * (arraySize-1));
int tmp=myArray[randNum];
myArray[randNum]=myArray[i];
myArray[i]=tmp;
}
Другое решение. Отметьте числа, которые были сгенерированы.
public static void main(String[] args) {
int[] randArray = new int[10];
int randNum = 0;
boolean[] isPresented = new boolean[32];
for (int i = 0; i < randArray.length; ) {
randNum = (int)(Math.random() * 31 + 1);
if(!isPresented[randNum]){
randArray[i] = randNum ;
isPresented[randNum] = true;
i++;
}
}
System.out.println(Arrays.toString(randArray));
}
Вы восстанавливаете случайное число каждый раз, когда вы проверяете строку, вместо того, чтобы сравнивать один и тот же номер со всеми значениями массива во внутреннем цикле.
Здесь вы должны проверить весь массив на одно и то же случайное число, и если вы найдете совпадение, установите k в 0 и восстановите случайное число, чтобы повторить попытку.
k=0; k < randArray.length
loop. Вы проверяете новое случайное число с одним индексом в randArray
вместо того же случайного числа с каждым индексом. Если вы создаете случайное число в j=0; ...
цикл вместо, если должен работать. Кроме того, вы можете избавиться от содержимого firstNumber, просто инициализируя randArray [0] новым случайным числом и выполняя цикл с j=1; j < randArray.length
.
Я бы использовал Shuffle Fisher-Yates, чтобы сделать это. Это самый быстрый способ, который я знаю, за счет небольшого избыточного потребления памяти. Но он не страдает от лишних попыток.
/*pseudocode; populate 'arr' to taste. I'd be tempted to write it long-hand*/
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 31};
/*Implement Fisher-Yates shuffle in its own scope block*/
{
Random random = new Random();
for (int i = arr.length - 1; i > 0; i--){
int r = random.nextInt(i + 1);
/*exhange r and i*/
int t = arr[r];
arr[r] = arr[i];
arr[i] = r;
}
}
/*ToDo - either rescale 'arr' or just use the first 10 elements*/
Во втором цикле for вы генерируете случайное число для каждой итерации цикла. Измените петлю, как показано ниже.
else {
// generate a random number before the loop begins
randNum = (int)(Math.random() * 31 + 1);
for (int k=0; k < randArray.length;) {
if(randArray[k] == randNum) {
k=0;
// generate a random number only if the number exists in the array
randNum = (int)(Math.random() * 31 + 1);
} else {
k++;
}
}
randArray[j] = randNum;
System.out.println(j);
}
Насколько мне известно, самый простой и эффективный способ создания (не очень большого) набора уникальных случайных чисел (он несколько похож на метод, предложенный Вирсабой):
1) генерировать ArrayList уникальных последовательных чисел, чтобы охватить весь необходимый диапазон
2) доступ к ArrayList с использованием случайного индекса и перемещение (получение и удаление из массива) записи в индексе.
Таким образом, после итераций ArrayList.size() вы получите результирующий массив уникальных случайных чисел.