我有一个案例,我需要选择一个随机项目,但我不知道项目的总数,我不想建立一个庞大的数组,然后选择一个项目。例如,这就是我现在所拥有的:
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,我使用新项目作为选定项目,如果不是忽略它。随着项目总数的增加,每个新项目的被选中机会都会相应减少。
这种方法“好”吗?它是否像构建数组并随后选择项目一样“随机”?它是否尽可能快?请随机指导我完成无知。 :)
答案 0 :(得分:14)
你正在做的事情会有效。
这是重述它可能会使算法更加清晰:
请注意,您应该能够通过1/x
(或rand.Next(0,x) == 0
和0
之间的任何其他整数来计算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”初始化为零。