0

I need to write a program to generate some random numbers without having two numbers fall in a certain range. Unfortunately, I need to do it at school and the only language I can use on the computers is Java (I would otherwise do it in C++). I know very little Java, and my program is giving me a stack overflow after generating 20 or so numbers. Could someone please explain why? The program is somewhat ugly, but I really need it ready in a hurry.

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);
    }
}
}

EDIT: Okay, so now, for some reason, the for loop (the one with y as a counter) is not running 40 times when I include the while loop. Can someone explain why this is happening?

4

6 回答 6

2

您的函数最终将无法返回主函数。

您将面临递归问题

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

由于数组 get 被 1 填满,这将继续执行函数调用,而不是实际成功返回。它将递归地执行函数,最终导致堆栈溢出。

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

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

于 2012-05-18T19:17:41.393 回答
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;
}

附带说明一下,当您接近列表末尾时,运行时也会很糟糕,但它不应该堆栈溢出。现在我考虑它可能会无限循环,您可能需要完全重新设计它。

于 2012-05-18T19:16:10.793 回答
0

这是预期的行为吗?“洗牌”

    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]);
    }
于 2012-05-19T20:53:09.783 回答
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 {}
于 2012-05-18T20:13:44.250 回答
0

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

此外,您永远不会改变previousNumberGenerateNumber因此无论生成的随机数如何,您都将始终走同一条路。

于 2012-05-18T19:09:05.757 回答
0

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

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

这段代码在 GenerateNumber 方法中,它会继续调用相同的方法。这就是原因。如果您想检查它,请删除该部分并尝试,它会编译得很好。要摆脱这种情况,请消除上述过程。

您可以通过使用循环、while 循环并将所有 if else 语句放入其中来完成

于 2012-05-18T19:32:06.103 回答