如果我不知道集合的大小,我可以从集合中选择一个随机元素吗?

时间:2011-01-13 11:57:44

标签: javascript algorithm random graph-theory

我正在编写一些JavaScript代码,如果该项符合某些要求,则应从画布中选择一个随机项。有不同种类的项目(圆形,三角形,正方形等),并且每种类型的项目数量通常不同。这些项目按层次排列(因此正方形可以包含几个圆圈,圆形可以包含其他圆形等等 - 它们都可以嵌套)。

现在,我选择随机项目的(原始)方法是:

  1. 递归遍历画布并构建一个(可能是巨大的!)项目列表
  2. 随机播放列表
  3. 从前面迭代洗牌后的列表,直到找到满足一些额外要求的商品。
  4. 这个问题是它不能很好地扩展。我经常遇到内存问题,因为递归深度太高或者项目总列表变得太大。

    我正在考虑重写这段代码,以便我在遍历画布时考虑选择元素 - 但如果我不知道总共有多少元素,我不知道如何“随机”选择一个元素

    有人知道如何解决这个问题吗?

3 个答案:

答案 0 :(得分:5)

您可以在不先创建列表的情况下执行此操作(抱歉我的C伪代码)

int index = 0;
foreach (element)
{
    if (element matches criteria)
    {
        index++;
        int rand = random value in [1 index] range
        if (1 == rand)
        {
            chosen = element;
        }
    }
}

数学计算结果表明,你有一个列表,其中3个元素符合标准,第一个元素将被选择的概率为:

1 * (1 - 1 / 2) * (1 - 1 / 3) = 1 * (1 / 2) * (2 / 3) = 1 / 3

选择第二个的可能性是:

(1 / 2) * (1 - 1 / 3) = (1 / 2) * (2 / 3) = 1 / 3

最后是第三个元素

1 / 3

这是正确答案。

答案 1 :(得分:5)

max_r = -1rand_node = null开始。通过树迭代。对于符合条件的每个节点:

r = random()
if r > max_r:
  rand_node = node
  max_r = r

最后rand_node将是一个随机选择的节点,只需要一次迭代。

答案 2 :(得分:0)

您可以递归地执行此操作:

  1. 遍历当前树级别,创建列表
  2. 从中选择一个随机节点(使用从0到list.Length的随机数)
  3. 重复,直到到达叶节点
  4. 这将使小子树中的项目被选中的概率更高。

    或者,您不需要构建列表,只需要跟踪项目数。这意味着第二次遍历树以获取所选项目,但您不需要额外的内存用于列表。