【问题标题】:Non-Uniform randomizer非均匀随机化器
【发布时间】:2010-08-10 17:24:00
【问题描述】:

我需要生成 6 个从 1 到 37 的唯一随机数;一开始我使用了一个简单的数组映射:

private int k=6, n=37;

public int[] Results ()
{
    // fill an array with numbers 1 2 3 . . . n
    int[] numbers = new int[n];
    for (int i = 0; i < numbers.length; i++)
        numbers[i] = i + 1;

    // draw k numbers and put them into a second array
    int result[] = new int[k];
    for (int i = 0; i < result.length; i++)
    {
        // make a random index between 0 and n - 1
        int r = (int) (Math.random() * n);
        // pick the element at the random location
        result[i] = numbers[r];
        // move the last element into the random location
        numbers[r] = numbers[n - 1];
        n--;
    }
    return result;
}

问题在于,在很多情况下,我得到了近乎均匀的分布(尤其是当我进行少于 10 次抽奖时),即:1、9、16、18、24、30 或 5、16、18、22 ,26,29

我真正需要的是一个真正的随机发生器,它可以给我这样的结果: 11,16,25,29,30,32 或 4,8,9,15,18,19 在 LESS 然后 10 抽奖。

我还看到了类似的 HashMap 实现:

import java.util.*;

public class RandomHash
{
    HashMap numbers = new HashMap() ;
    Random rnd_gen = new Random() ;

    RandomHash()
    {
        for(;;)
        {
            int rnd_num = rnd_gen.nextInt() ;
            Integer rnd_num_obj = new Integer(rnd_num) ;

            if (! numbers.containsKey(rnd_num_obj) )
            {
                numbers.put(rnd_num_obj, rnd_num_obj) ;
                /* Do whatever with the number */
                break ;
            } /* else loop and get another rnadom num */

        } /*end for*/
    }
}

问题是我目前不知道如何将随机化器和哈希图分别绑定到 6 和 32。 hashmap 会给出更混乱的结果吗?

【问题讨论】:

  • 定义“真正的随机”数字,并说明为什么你得到的输出不是真正随机的。
  • 什么是“非均匀”?你的意思是“不统一”吗?您需要什么发行版?

标签: java random hashmap


【解决方案1】:

你可以在一个随机数调用中做到这一点! 10 是 9 太多了 :-)

请注意,您的 6 个号码恰好有 37 种选择 6 种可能性。

所以,您需要做的就是选择一个介于 1 和 2324784 之间的随机数(即 37 选择 6)。

然后使用映射得到6个元素的对应组合。有关映射的示例,请参见此处:Generating the mth Lexicographical Element of a Mathematical Combination

MSDN 代码的 Java 端口在这里:http://the-lost-beauty.blogspot.com/2010/07/generating-combinations-in.html

【讨论】:

  • 嗨,白痴,我需要有关此代码的 java 实现方面的帮助。对我来说 C# 的不匹配太多了:-/
【解决方案2】:

你要求随机数,这就是你得到的。您的两个示例:11,16,25,29,30,32 和 4,8,9,15,18,19 比您认为均匀分布的结果更不可能。

例如,让我们看看您的最后一个结果,为了简化起见,假设您希望所有数字都小于或等于 19。如果您选择 1 到 32 之间的单个数字,您有 19/32 的机会(大约 59 %) 为 19 或更少。如果您在 1 到 32 之间选择 6 个不同的数字,那么所有这些数字都为 19 或更少的可能性不到 3%。

当你的代码运行 100 次时,我实际上得到了五个满足要求的列表,这比统计预期的多两个:

[3, 8, 13, 16, 18, 19]

[2, 3, 6, 8, 10, 14]

[2, 6, 7, 8, 13, 18]

[4, 5, 9, 10, 11, 12]

[8、12、13、15、16、17]

【讨论】:

    【解决方案3】:

    我只是洗牌第一个数组(在初始化步骤之后)并取前 6 个元素。你可以使用类似的东西

    Collections.shuffle( Arrays.asList(array) );
    

    使用语言的内置函数来打乱数组。

    如果您从 1,000,000 个元素中进行选择,这可能是一个性能问题,但我认为只有 37 个元素是一个更清晰的解决方案。

    【讨论】:

    • 那将使用 32 个随机数调用,不是吗?我相信 OP 特别希望不超过 10 个。事实上,只有一个电话是可能的:看我的回答。
    • “少于 10 次抽奖”。我将其解释为 10 个随机数调用。在任何情况下,改组更实用且更不容易出错,并且对于 32 个数字可能不会成为性能/准确性问题。所以+1 :-)
    • @Moron:在二读时,我注意到他确实说了两次。他说“尤其是当我的抽奖次数少于 10 次时”,这听起来不像是要求,但在下一段中肯定是。
    【解决方案4】:

    Linear congruential generator modulo 37, with suitably chosen parameters?

    或者,

    List l = Arrays.asList(numbers);
    Collections.shuffle(l);
    return l.subList(0,k).toArray();
    

    请注意,它期望数字是一个 Object[] 并返回另一个 Object[]。

    【讨论】:

    • 嗨,tc,我如何/在哪里在我的代码中实现它?请你把它写下来好吗? THNX
    【解决方案5】:

    这是一个非均匀分布:

    return new int[]{1,2,3,4,5,6};
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-04
      • 2020-09-07
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多