StackOverflow生成随机数而没有两个数字落在一定范围内

时间:2012-05-18 18:59:49

标签: java stack-overflow

我需要编写一个程序来生成一些随机数,而不会有两个数字落在一定范围内。不幸的是,我需要在学校这样做,我可以在计算机上使用的唯一语言是Java(否则我会用C ++编写)。我知道Java很少,并且我的程序在生成20个左右的数字后给了我堆栈溢出。有人可以解释一下原因吗?该计划有点难看,但我真的需要赶紧准备好。

import java.io.*;
import java.util.*;

public class RandomNumbers {
public static int GenerateNumber(int previousNumber, int[] numberUsed) {
    Random random = new Random();
    int number = random.nextInt(39);
    if (previousNumber >= 1 && previousNumber <= 9) {
        while (number >= 1 && number <= 9)
            number = random.nextInt(39) + 1;
    } else if (previousNumber >= 10 && previousNumber <= 17) {
        while (number >= 10 && previousNumber <= 17)
            number = random.nextInt(39) + 1;
    } else if (previousNumber >= 18 && previousNumber <= 32) {
        while (number >= 18 && previousNumber <= 32)
            number = random.nextInt(39) + 1;
    } else if (previousNumber >= 33 && previousNumber <= 41) {
        while (number >= 32 && number <= 41)
            number = random.nextInt(39) + 1;
    }
    return number;
}

public static void main(String[] args) {
    int[] numberUsed;
    numberUsed = new int[40];
    for (int i = 0; i < 40; ++i) {
        numberUsed[i] = 0;
    }
    int previousNumber = 0;
    for (int y = 0; y < 40; ++y) {
        int number = 1;
        while (numberUsed[ number = GenerateNumber
                         (previousNumber, numberUsed) ] != 0);
        numberUsed[number] = 1;
        previousNumber = number;
        System.out.println(y);
    }
}
}

编辑:好的,现在,由于某种原因,当我包含while循环时,for循环(y作为计数器的循环)没有运行40次。有人可以解释为什么会这样吗?

6 个答案:

答案 0 :(得分:2)

你的功能最终会有一个问题,永远不会回到主。

您将面临

中的递归问题
if (numberUsed[number] != 0) {
    return GenerateNumber(previousNumber, numberUsed);
}

当数组得到1时,这将继续执行函数调用而不是实际成功返回。它会以递归方式执行函数,最终导致堆栈溢出。

再次调用该函数时,您的参数(previousNumber和numberUsed)与上次执行相同,没有任何变化。你继续遇到同样的问题,因为击中非零的机会是如此之高,所以递归只是永远堆积起来并最终崩溃。

你应该摆脱函数中的if语句,只需将数字返回main,然后在那里进行检查。

答案 1 :(得分:0)

你从一个零出的数组开始,你逐渐填充1并且永远不会将它们重置为0.当数组的大多数元素都是非零时,你很有可能调用{{1在一个非常深的嵌套中递归,这是你经历的。

此外,您永远不会更改GenerateNumber中的previousNumber,因此无论生成的随机数如何,您都将始终沿着相同的路径前进。

答案 2 :(得分:0)

在盯着这一段时间之后,我想我找到了一个有效的解决方案。它仍然非常难看,但你似乎对此很好。

public static int GenerateNumber(int previousNumber, 
                                int[] numberUsed) {
    Random random = new Random();
    int number = random.nextInt(39);
    while (numberUsed[number] != 0) {
        number = random.nextInt(39);
        if (previousNumber >= 1 && previousNumber <= 9) {
            while (number >= 1 && number <= 9)
                number = random.nextInt(39) + 1;
        } else if (previousNumber >= 10 && previousNumber <= 17) {
            while (number >= 10 && previousNumber <= 17)
                number = random.nextInt(39) + 1;
        } else if (previousNumber >= 18 && previousNumber <= 32) {
            while (number >= 18 && previousNumber <= 32)
                number = random.nextInt(39) + 1;
        } else if (previousNumber >= 33 && previousNumber <= 41) {
            while (number >= 32 && number <= 41)
                    number = random.nextInt(39) + 1;
        }
    }
    return number;
}

另一方面,当你走向列表末尾时,运行时也会很恶劣,但不应该堆栈溢出。现在我想起来也可能是无限循环,你可能需要完全重新设计它。

答案 3 :(得分:0)

StackOverFlow因为方法/构造函数等的重叠而发生。我在这里,

if (numberUsed[number] != 0) {
        return GenerateNumber(previousNumber, numberUsed);
    }

此代码位于GenerateNumber方法内部,并且继续调用相同的方法。这就是原因。如果你想检查它,删除该部分并尝试,它将编译正常。要摆脱这种情况,请排除上述过程。

你可以通过循环,while循环,并将所有if else语句放在

中来实现

答案 4 :(得分:0)

此代码检测到死胡同并继续重新启动直到它到达终点(通常只执行一次或两次重试)。它还直接从收集的允许选择序列中选择一个随机数,因此任何单一尝试都不会有随机运行时间。

import java.util.Arrays;
import java.util.BitSet;
import java.util.Random;

public class RandomNumberGenerator {
  static final Random random = new Random();
  static final BitSet usedNumbers = new BitSet(40);
  static final int[] ticks = {0, 1, 10, 18, 33, 41};
  static int previousNumber;

  public static int generateNumber() {
    for (int i = 1; i < ticks.length; i++)
      if (previousNumber < ticks[i])
        return generateOutsideRange(ticks[i-1], ticks[i]);
    return generateOutsideRange(0, 0);
  }

  static int generateOutsideRange(int low, int high) {
    final int[] numsToChoose = new int[40];
    int choiceLimit = 0;
    for (int i = (low > 1? 1 : high); i < 41; i = (++i == low? high : i))
      if (!usedNumbers.get(i)) numsToChoose[choiceLimit++] = i;
    if (choiceLimit == 0) throw new CulDeSacException();
    final int r = numsToChoose[random.nextInt(choiceLimit)];
    usedNumbers.set(r);
    previousNumber = r;
    return r;
  }

  public static void main(String[] args) {
    while (true) try {
      usedNumbers.clear();
      previousNumber = -1;
      final int[] rands = new int[40];
      for (int i = 0; i < rands.length; i++) rands[i] = generateNumber();
      System.out.println(Arrays.toString(rands));
      break;
    } catch (CulDeSacException e) { System.out.println("Retry"); }
  }
}

class CulDeSacException extends RuntimeException {}

答案 5 :(得分:0)

这是指定行为吗? &#34;改组阵列&#34;

    ArrayList<Integer> numbers = new ArrayList<Integer>();
    int[] scrambled = new int[40];
    Random rnd = new Random();
    for(int i=0;i<scrambled.length;i++){
        numbers.add(i+1);
    }
    int idx=0;
    while(!numbers.isEmpty()){
        int pos = rnd.nextInt(numbers.size());

        scrambled[idx] = numbers.get(pos);
        numbers.remove(pos);

        idx++;
    }
    for(int i=0;i<scrambled.length;i++){
        System.out.println(scrambled[i]);
    }