【问题标题】:How to be sure that random numbers are unique and not duplicated?如何确保随机数是唯一的且不重复?
【发布时间】:2012-03-04 17:16:00
【问题描述】:

我有一个生成随机数的简单代码

SecureRandom random = new SecureRandom();
...
public int getRandomNumber(int maxValue) {
    return random.nextInt(maxValue);
}

上面的方法被调用了大约 10 次(不是在循环中)。我想确保所有数字都是唯一的(假设 maxValue > 1000)。

我可以确定每次拨打电话时都会收到唯一的号码吗?如果没有,我该如何解决?

编辑:我可能含糊其辞。我想避免手动检查我是否真的得到了唯一的数字,所以我想知道是否有更好的解决方案。

【问题讨论】:

  • 随机!=唯一。事实上,通常情况恰恰相反。
  • 要么在释放之前检查之前使用的数字,要么使用随机 shuffle 而不是随机数字。如果你只得到 10 个数字,后者就大材小用了。我支持 Oli 的上述回答,因为您有两个问题——随机性和唯一性。
  • 编辑问题以明确唯一性与随机性的术语
  • @skaffman 谢谢。我犯了一个错误......现在很清楚了

标签: java random unique


【解决方案1】:

有不同的方法可以实现这一点,哪种更合适取决于您需要从多少数字中选择多少。

  • 如果您要从大量潜在数字中选择少量随机数,那么您最好将先前选择的数字存储在一个集合中并“手动”检查重复项。大多数情况下,您实际上不会得到副本,并且实际上该测试的成本几乎为零。这听起来可能不优雅,但实际上并没有听起来那么糟糕。
  • 一些底层随机数生成算法不会在其“原始”级别产生重复。因此,例如,一种称为XORShift 生成器的算法可以有效地生成一定范围内的所有数字,并且无重复地打乱。所以你基本上在序列中选择一个随机起点,然后只生成接下来的 n 个数字,你就知道不会有重复。但在这种情况下,您不能随意选择“最大值”:它必须是相关生成器的自然最大值。
  • 如果可能的数字范围很小,但您需要选择的数字数量在该范围的几个数量级之内,那么您可以将其视为随机选择问题。例如,要在 10,000,000 范围内选择 100,000 个不重复的数字,我可以这样做:

    设 m 是到目前为止我选择的随机数的数量

    对于 i = 1 到 10,000,000

    生成一个随机(浮点)数,r,范围为 0-1

    如果 (r

    随机播放列表,然后根据需要从列表中依次选择数字

但显然,如果您需要在整个数字范围中选择相当大的比例,则选择后一种选项很有意义。对于选择 1 到 10 亿范围内的 10 个数字,您将生成 10 亿个随机数,当您只检查重复项时,您实际上不太可能得到重复项,最终只会生成 10 个随机数数字。

【讨论】:

  • 真的很有帮助。 XORShift 看起来很有趣。谢谢
【解决方案2】:

随机序列并不意味着所有值都是唯一的。序列1,1,1,1 与序列712,4,22,424 完全一样。

换句话说,如果你想保证一个唯一的数字序列,一次生成 10 个,检查你选择的唯一性条件并存储它们,然后从该列表中选择一个数字,而不是生成一个随机数在你的 10 个地方的数字。

【讨论】:

    【解决方案3】:

    每次你拨打Random#nextInt(int)你都会得到

    一个伪随机、均匀分布的 int 值,介于 0(含)之间 和指定的值(不包括)。

    如果您想要x 唯一号码,请不断获取新号码,直到您拥有那么多号码,然后从该列表中选择您的“随机”号码。但是,由于您正在过滤生成的数字,它们将不再是真正的随机数。

    【讨论】:

      【解决方案4】:

      对于这么少的可能值,一个简单的实现是将你的 1000 个整数放在一个列表中,并有一个循环,在每次迭代时生成一个介于 0 和 list.size() 之间的随机数,选择数字存储在此索引中,并将其从列表中删除。

      【讨论】:

      • 我按照你的回答学到了很多,你是这样一个贡献者,1000 个整数列表和查找已经生成的数字不是很昂贵吗?
      • 这完全取决于调用了多少次,在什么情况下等等。如果在一个称为十亿次的紧密循环中完成,选择更好的方法可能会很有用。如果它只需要完成一次或两次,或者在大部分时间都花在等待用户输入上的应用程序中,你不在乎。 (PS:我不知道我有一个粉丝;-))
      • 你的分析和回答值得粉丝群。哈哈!。我确实回答了,但我的回答停在 A-G,你的回答涵盖了完整的基础 A-Z。一切顺利。
      【解决方案5】:

      这是代码以内存为代价在 CPU 上非常高效。每个潜在价值成本sizeof(int) * maxValue。无符号整数的最大值为 65535。 long 可以以大量内存为代价 2000 字节用于 1000 个 16 位整数的值。

      数组的全部目的是说你之前有没有使用过这个值1 = yes '其他 = 没有 'while 循环将不断生成随机数,直到找到唯一值。 '在找到一个好的随机值后,它会将其标记为已使用,然后返回它。 '请注意变量 a 的范围,就好像它超出了您的数组可以擦除的范围一样。 ' 我在 c 中使用过它并且它有效。 ' 可能需要一些复习才能使其在 Java 中工作。

      unsigned int a(1000);
      
      public int getRandomNumber(int maxValue) {
        unsigned int rand;
      
        while(a(rand)==1) {
          rand=random.nextInt(maxValue);
          if (a(rand)!=1) { a(rand)=1; return rand;}
        }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-06
        • 1970-01-01
        • 1970-01-01
        • 2017-06-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多