选择随机项目,但不知道项目总数

时间:2010-03-07 05:50:55

标签: algorithm random

我有一个案例,我需要选择一个随机项目,但我不知道项目的总数,我不想建立一个庞大的数组,然后选择一个项目。例如,这就是我现在所拥有的:

List<string> items;
while (true)
{
    string item = GetNextItem();
    if (item == null)
        break;
}
int index = random.GetNext(0, items.count);

正如你所看到的,我正在构建一个我真正不需要的巨大集合,我只需要一个介于0和项目数之间的随机数。这是我正在考虑做的事情,并且它有效,但我想知道那里的任何专家是否可以找到它的错误:

int index = -1;
int total;
string selectedItem;
while (true)
{
    string item = GetNextItem();
    if (item == null)
        break;

    ++total;
    int rnd = random.Next(0, total);
    if (rnd == total- 1)
    {
        index = total- 1;
        selectedItem = item;
    }
}

这给了我索引号和随机选择的项目。我在这背后的想法是,当有3个项目时,例如,我选择0到2之间的随机数(包括),如果它等于2,我使用新项目作为选定项目,如果不是忽略它。随着项目总数的增加,每个新项目的被选中机会都会相应减少。

这种方法“好”吗?它是否像构建数组并随后选择项目一样“随机”?它是否尽可能快?请随机指导我完成无知。 :)

4 个答案:

答案 0 :(得分:14)

你正在做的事情会有效。

这是重述它可能会使算法更加清晰:

  1. 选择第一项,有一项 它将有100%的可能性 选择
  2. 如果有第二项, 它将有1/2的机会 替换当前的选择(如果你做数学,那么它有50%的几率成为第一个项目,50%的几率成为第二个项目)
  3. 如果 有第三项,有一项 它将取代1/3的几率 当前选择(再次,数学每个项目的概率为1/3)
  4. 如果有 第四项,有1/4的机会 它将取代目前的 选择
  5. ......等......
  6. 请注意,您应该能够通过1/x(或rand.Next(0,x) == 00之间的任何其他整数来计算x - 1机会;您不必麻烦使用total - 1

    这实际上是一种非常巧妙的方法;最初我以为没有任何好办法做你所要求的事情!

答案 1 :(得分:2)

你的方法看起来不错,是的。

1 item =被选中

2项= 50%的几率你选择第二项替换第一项

3项= 33%的几率你选择第3项,67%的几率你选择前两项之一

4项=你选择第4项的几率为25%,你选择的几率为75%......

...

因此,与大多数其他回复相反,我认为你有一个工作解决方案可以提供均匀的概率分布。

您可以简化随机检查:

 int rnd = random.Next(0, total);
    if (rnd == 0)

因为你测试的总1值中的哪一个与获得1 / n概率无关。

答案 2 :(得分:0)

我们可以通过归纳来证明这一点 这是真的1;
如果n是真的; n + 1确实如此;
=&GT;概率。前n个元素的选择= 1 / n
=&GT; sice prob。选择第(n + 1)个元素是1 /(n + 1)
=&GT;不选择第(n + 1)个元素的概率是n /(n + 1)
=&GT;添加第(n + 1)个元素后,前n个元素的选择概率= 1 / n *(n / n + 1)= 1 / n + 1

答案 3 :(得分:-1)

在您的第一个代码段中,您使用items.count,因此您知道您拥有多少元素。您需要知道此数字,以便每个元素都有相同的被选中机会。

正如您所写,您生成一个随机数i,使得0 <= i&lt; items.count,然后您尝试快速访问列表的元素i。 (链表可能不是数据结构的好选择。)

如果您对项目数量的估计值很好,则可以使用此项而不是items.count。

在您的第二个代码段中,您可能需要将“total”初始化为零。