如何在少于O(n)的时间内在std :: set中选择一个随机元素?

时间:2011-11-28 20:59:46

标签: c++ set stl-algorithm

This question有一个附加约束。

我愿意允许不均匀的选择,只要它不偏不倚。

鉴于“sets are typically implemented as binary search trees”并且我希望它们包含某种深度或大小信息以进行平衡,我希望你可以对树进行某种加权随机游走。但是我不知道有任何远程可移植的方法。

编辑:约束不是分摊的时间。

5 个答案:

答案 0 :(得分:6)

引入大小等于set的数组。使数组元素保存集合中每个元素的地址。生成由数组/集大小限制的随机整数R,在由R索引的数组元素中选择地址,并取消引用它以获取集合的元素。

答案 1 :(得分:3)

我不知道如何只用std::set来做,所以你可能需要一个不同的数据结构。就像Victor Sorokin所说,你可以将一个集合与一个向量组合起来。使用set<T>map<T, size_t>代替vector< map<T, size_t>::iterator >。每个键的值是向量的索引,向量的每个元素都指向map元素。向量元素没有特定的顺序。添加元素时,将其放在向量的末尾。删除元素并且它不是向量中的最后一个元素时,将最后一个元素移动到已删除元素的位置。

答案 2 :(得分:1)

IF 您知道集合中元素的分布,您可以随机选择密钥(使用相同的分布)并使用std::set::lower_bound。如果不是那么多。

int main() {
    std::set<float> container;
    for(float i=0; i<100; i += .01)  
        container.insert(i);
    //evenish distribution of 10000 floats between 0 and 100.
    float key = std::rand() *10000f / RAND_MAX; //not random, sue me
    std::set<float>::iterator iter = container.lower_bound(key); //log(n)
    std::cout << *iter;
    return 0;
}

答案 3 :(得分:0)

您可以使用此构造函数

制作地图的随机排序副本
template <class InputIterator>
set(InputIterator f, InputIterator l,
    const key_compare& comp)

..并传递一个比较键的哈希值(或其他一些确定性传播函数)的比较器。然后根据这个新地图取“最小”键。

您可以构建一次地图,并在几个“随机”元素请求中分摊费用。

答案 4 :(得分:0)

std::unordered_set<int> s

1)在R

中随机min(s)..max(s)

2)R中的s:返回R

3)

newIter = s.insert(R).first;
newIter++;
if (newIter == s.end()) {
    newIter = s.begin();
}
auto result = *newIter;
s.erase(R);
return result;

对于有序集(std :: set),概率取决于元素之间的距离。 unordered_set由哈希随机化。

我希望这可以提供帮助。

PS将std::set<V>转换为std::set<std::pair<int, V>>(其中第一个元素是第二个散列)使此方法适用于任何可散列V.