我正在尝试生成一组随机数。每个数组条目都有一个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重复两次。如果我再次运行代码,您可以看到存储的重复数字。
从逻辑上讲,我无法弄清楚为什么会这样做。它可能很简单,但我看不到它。
我是编程新手,这是我认为我会测试我的知识的。
答案 0 :(得分:3)
您生成唯一随机数的方法是错误的,因为当您到达数组中的最后一个数字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;
}
答案 1 :(得分:2)
每次检查行时都会重新生成随机数,而不是将相同的数字与内部循环中的所有数组值进行比较。
你应该在这里做的是检查相同随机数的整个数组,如果你发现巧合,将k设置为0并重新生成随机数再试一次。
答案 2 :(得分:2)
您可以尝试以下代码:
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
答案 3 :(得分:2)
我会使用 Fisher-Yates shuffle来执行此操作。这是我所知道的最快的方式,代价是内存消耗过多。但它不会受到任何重试开销的影响。
/*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*/
答案 4 :(得分:2)
另一种解决方案。 标记生成的数字。
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));
}
答案 5 :(得分:1)
在第二个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);
}
答案 6 :(得分:0)
据我所知,生成(非常大)一组独特随机数的最简单,最有效的方法是(它与Bathsheba建议的方法有些相似):
1)生成一个唯一序列号的ArrayList,以涵盖所有需要的范围 2)使用随机索引访问ArrayList并移动(从数组中获取和删除)索引处的条目。
这样,在ArrayList.size()迭代之后,你将得到一个唯一随机数的结果数组。