这个问题增加了一个限制条件。
只要不过于偏向某一侧,我愿意允许非均匀选择。
由于"集合通常是实现为二叉搜索树的",而且我预计它们会包含一些深度或大小信息来进行平衡,因此我认为您可以对树进行加权随机游走。 但是,我不知道任何适用于多种平台的方法。
编辑:限制条件不是分摊时间。
这个问题增加了一个限制条件。
只要不过于偏向某一侧,我愿意允许非均匀选择。
由于"集合通常是实现为二叉搜索树的",而且我预计它们会包含一些深度或大小信息来进行平衡,因此我认为您可以对树进行加权随机游走。 但是,我不知道任何适用于多种平台的方法。
编辑:限制条件不是分摊时间。
介绍一个大小与集合相等的数组。使数组元素保持集合中每个元素的地址。生成随机整数 R
,其范围在数组/集合大小内,选择数组中由索引为 R
的元素标记的地址,并对其进行取消引用以获取集合的元素。
我不认为只用std::set
就可以做到,所以你可能需要一个不同的数据结构。像Victor Sorokin所说的那样,你可以将一个set与一个vector组合使用。不要使用set<T>
,而是使用map<T, size_t>
,再加上vector< map<T, size_t>::iterator >
。每个键的值都是向量中的一个索引,向量的每个元素指向地图元素。向量元素没有特定的顺序。当你添加一个元素时,把它放在向量的末尾。当你删除一个元素并且它不是向量中的最后一个元素时,将最后一个元素移动到删除的元素位置。
如果你知道集合中元素的分布,你可以随机选择键(具有相同分布)并使用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;
}
通过使用这个构造函数,您可以制作一个随机顺序的地图副本。
template <class InputIterator>
set(InputIterator f, InputIterator l,
const key_compare& comp)
...并传入一个比较器,该比较器比较键的哈希值(或其他确定性扩展函数)。
然后根据这个新映射获取“最小”的键。
您可以一次构建映射,并在多个请求“随机”元素中分摊成本。
std::set
是一个哈希表,否则这比O(n)更糟糕。 - Andres Jaan TackO(N log(N))
生成副本,然后在重新生成之前将其耗尽,则每个项目的成本为 O(log(N))
。 - phsstd::unordered_set<int> s
:min(s)..max(s)
中随机取一个数 R
2)如果 R
在 s
中:返回 RnewIter = s.insert(R).first;
newIter++;
if (newIter == s.end()) {
newIter = s.begin();
}
auto result = *newIter;
s.erase(R);
return result;
std::set<V>
转换为std::set<std::pair<int,V>>
(其中对第二个元素进行哈希的第一个元素是哈希)使得此方法适用于任何可哈希的V。
std::set
没有被定义为二叉搜索树。其复杂度要求基本上意味着它不能是其他任何类型的数据结构,但是树结构不是标准的一部分,因此也不包含在接口中。(如果你有一个真正平衡的树,你可以通过随机选择左或右孩子直到到达底部,在O(log n)时间内选择一个随机元素)。也许下一个标准应该提出一个“random()”接口;毕竟,已经有一个“random_shuffle”算法了,并且这并没有什么不同。(顺便说一下,在“std::unordered_set”中可以在O(1)时间内完成。) - Kerrek SBrandom()
接口。 - BCS