【问题标题】:Generate unique random number between 0 and 1000 [duplicate]生成0到1000之间的唯一随机数[重复]
【发布时间】:2012-05-21 21:35:19
【问题描述】:

可能重复:
Generating Unique Random Numbers in Java

如何生成 0 到 1000 之间的随机数,并继续将在 0 到 1000 之间生成的唯一随机数传递给特定方法。因此,为此我生成了 0 到 1000 之间的数字,并在 List 中插入了 0 到 1000 之间的唯一随机数,以便我们可以比较我们生成的随机数是否已经存在于列表中。如果它存在,则再次生成它。但不知何故,我相信下面的代码有时会失败。

public class Testing4 {
    private static List<Integer> randomNumber;
    private static Random r = new Random();
    private static int rand;
    private static int endRange = 1000;

    public static void main(String args[]) throws IOException {

        randomNumber = new ArrayList<Integer>();

        for (int i = 1; i<= endRange; i++) {
            rand = r.nextInt(endRange);

            if(randomNumber.contains(rand)) {
                rand = r.nextInt(endRange);
            } else {
                randomNumber.add(rand);
            }

        // Pass the unique random number between 0 and 1000 to this method      
                randomNumberMethod(rand);

        }
    }
}

【问题讨论】:

  • 我没有想到它的代码,但基本上:生成一个从 0 到 1000 的整数列表并随机播放,然后一次返回每个值.这比尝试跟踪您已经看到的内容要少得多。
  • 你是认真的吗?我花了 10 分钟写了一个很棒的答案。它被锁定了。我很沮丧。
  • @Andrius,你能在这里复制粘贴,这样我就可以看到最有效的方法是什么?或者我可以提供我的电子邮件地址。
  • 好吧,我的答案已经被破坏了。只需使用他们链接到您的答案 :) 感谢您非常有礼貌 :)

标签: java random


【解决方案1】:

您实际上是在以随机顺序生成一个从 0 到 1000 的数字列表。您可以通过以下方式更有效地实现这一目标:

public class Testing4 {
    private static List<Integer> randomNumber;
    private static int endRange = 1000;

    public static void main(String args[]) throws IOException {

        randomNumber = new ArrayList<Integer>(endRange);

        for (int i = 0; i<= endRange; i++) {                
            randomNumber.add(i);
        }

        Collections.shuffle(randomNumber);

        for (int i = 0; i<= endRange; i++) {                
            // Pass the unique random number between 0 and 1000 to this method      
            randomNumberMethod(randomNumber.get(i));
        }
    }
}

想想当你到达 999 时会发生什么 - 你将有 999 分之一的机会在每次循环中“猜测”剩余的可用数字。

【讨论】:

  • 这在某些时候给了我 IndexOutOfBoundException。
  • 答案已更新以更正。您的原始代码从 1-1000 循环,但我从您的文本中看到您实际上想要 0-1000。我的代码在第二个循环中错误地从 1 开始,导致 IndexOutOfBoundException,但如果两者都更改为从 0 开始,您将获得您正在寻找的行为。
  • 感谢 Malcolm 的更新,所以如果我需要 0 到 1001 之间的随机数,我可以在 for 循环中更改为 i&lt;endRange?对吗?
  • 是的,只需更改 endRange。 Java 中的 BTW 常量通常声明为 final 并以大写形式写入,即 private static final int END_RANGE = 1000;
【解决方案2】:

要生成 0 到 1000 之间的唯一数字列表,请执行以下操作:

  • 创建一个包含从 0 到 1000 的所有数字的列表
  • 使用 Collections.shuffle() 打乱列表
  • 从列表中取出您需要的第一个数字。

在某些情况下需要更复杂的算法,但如果可能的数字范围和您需要选择的项目数量都在 1000 左右,那么您真的不妨只取第一个 n 随机打乱的所有可能性列表中的数字。

如果你确实想做你建议的事情,那么:

  • 按照另一位发帖人的建议使用 while 循环
  • 使用 Set 而不是列表来存储已选择的值。

但是,这会变得低效,因为要选择的项目数量趋向于可能的项目数量(例如,如果您从可能的 1000 个数字中选择 10 个,那么就可以了;如果您从可能的 1000 个中重新选择 900 个,这将变得效率低下,因为每次都需要拒绝越来越多的数字,然后才能找到以前未选择的数字)。

【讨论】:

  • 你能根据我的代码向我展示一个示例吗?
【解决方案3】:

从代码检查中,我看不出这个方法中有什么会阻止它工作,它只是非常低效。

一方面,检查该数字是否是您所见过的 randomNumber.contains(rand) 将花费越来越多的时间,因为您生成的数字越多,因为每次执行此操作时,您都必须将其与中的每个数字进行比较直到你找到一个匹配的或者你已经尝试了列表中的每个数字。一个更好的方法是使用HashSet 而不是一个列表,这样可以使每个成员资格测试花费相同的时间,而不管您在其中放入了多少东西。

通过注意您可能问错了问题,可以进行第二次更重要的优化。您是要生成唯一的随机数,还是要以随机顺序生成 1 和 endRange 之间的每个数字?如果您想要每个数字(甚至是其中的重要部分),将 1 到 1000 的每个数字放入一个列表中,然后使用 Collections.shuffle 将它们随机排列会快很多。所以你的生成代码将是:

java.util.List<Integer> nums = new java.util.ArrayList<Integer>(1001);
for (int i = 0; i <= 1000; i++)
{
   nums.add(new Integer(i));
}
java.util.Collections.shuffle(nums);

【讨论】:

    【解决方案4】:

    如果连续生成 ArrayList 中已存在的 2 个数字,您的代码将失败。它将使用第二个数字,无论它是否重复。 if 语句应该是一个 while 循环(不断尝试,直到它生成一个唯一的循环)。

    public class Testing4 {
        private static HashSet<Integer> randomNumber;
        private static Random r = new Random();
        private static int rand;
        private static int endRange = 1000;
    
        public static void main(String args[]) throws IOException {
    
            randomNumber = new HashSet<Integer>();
    
            for (int i = 1; i<= endRange; i++) {    
                do
                {
                   rand = r.nextInt(endRange);
                }
                while(randomNumber.contains(rand));
    
                randomNumber.add(rand);
    
                // Pass the unique random number between 0 and 1000 to this method      
                randomNumberMethod(rand);
    
            }
        }
    }
    

    edit:根据 cmets,您应该使用 do/while 和散列数据结构而不是 arraylist 来加速重复查找。最后的修改在上面的代码中。

    【讨论】:

    • “do while”循环在这里似乎更合适。
    • 这是真的(为了整洁),我将编辑我的答案。
    • 这种方法的主要问题是当randomNumber.length() 接近endRange 时它会显着减速。当randomNumber 为空时,加法将只需要一次while 循环迭代。当它快满时,大约需要endRange 次迭代才能成功。
    • 实际上同意,就优化而言。 HashSet 而不是 ArrayList 会大大加快速度。我最初的回答是为了正确而不是效率。
    猜你喜欢
    • 2015-11-10
    • 2013-07-31
    • 2014-06-16
    • 2012-01-12
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多