Can I choose a random element from a set if I don't know the size of the set?

元气小坏坏 提交于 2019-12-10 10:29:19

问题


I'm writing a bit of JavaScript code which should select a random item from a canvas if the item meets certain requirements. There are different kinds of items (circles, triangles, squares etc.) and there's usually not the same number of items for each kind. The items are arranged in a hierarchy (so a square can contain a few circles, and a circle can contain other circles and so on - they can all be nested).

Right now, my (primitive) approach at selecting a random item is to:

  1. Recursively traverse the canvas and build a (possibly huge!) list of items
  2. Shuffle the list
  3. Iterate the shuffled list from the front until I find an item which meets some extra requirements.

The problem with this is that it doesn't scale well. I often run into memory issues because either the recursion depth is too high or the total list of items becomes too large.

I was considering to rewrite this code so that I consider choosing elements as I traverse the canvas - but I don't know how I could "randomly" choose an element if I don't know how many elements there are in total.

Does anybody have some idea how to solve this?


回答1:


Start with max_r = -1 and rand_node = null. Iterate through the tree. For each node meeting the criteria:

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

At the end rand_node will be a randomly selected node with only a single iteration required.




回答2:


You can do this without first creating a list (sorry for my C pseudo code)

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

The math works out, say you have a list where 3 of the elements match the criteria, the probability that the first element will be chosen is:

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

The probability of the second being chose is:

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

and finally for the third element

1 / 3

Which is the correct answer.




回答3:


You could recursively do this:

  1. Traverse the current tree level, creating a list
  2. Select a random node from it (using a random number from 0 to list.Length)
  3. Repeat until you get to a leaf node

that would give items in small subtrees a higher probability of being selected though.

Alternatively, you don't need to build a list, you only need to keep track of the number of items. That would mean traversing the tree a second time to get to the selected item, but you wouldn't need the extra memory for the list.



来源:https://stackoverflow.com/questions/4679744/can-i-choose-a-random-element-from-a-set-if-i-dont-know-the-size-of-the-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!