从O(log(n))时间的std :: set中随机选择一个元素

时间:2018-08-21 15:50:08

标签: c++ set random-access

是否可以从std::set中的O(log(n))中随机选择一个元素,或者 O(1)时间更好吗?它不需要非常均匀的分布,而只是相当随机的东西 (尽管显然更好)

std::set::extract似乎很有希望 因为它有可能在恒定时间内将set分成两半,但是我找不到 确定靠近根节点的好方法,以及我可以的node_type文档 找到的细节不多。

如果所有其他方法均失败,则可以使用我认为可以的随机密钥将内容复制到std::mapO(n log(n))时间,这将使我分期O(log(n))时间,但这不是首选解决方案 因为在我不想要所有东西的情况下,这会需要一些开销

2 个答案:

答案 0 :(得分:2)

如果集合中的元素本身在某个值域中均匀分布,那么您可以在该域中生成一个随机值,并使用std::set::lower_bound获得集合中包含的第一个元素不少于比随机值。

鉴于您不需要非常均匀的分布,则对集合中元素的均匀性要求可能不是非常必要。选择一个元素的可能性取决于它与前一个元素的相对距离。

对于均匀分布,我认为没有比*std::next(std::begin(s), random_index)更好的了,因为复杂度是线性的。


对于具有均匀分布和对数渐近复杂度的良好通用解决方案,您需要除std::set之外的其他数据结构。

尤其是,Order statistic tree是一个不错的选择,它通过在节点中添加子树的大小来增强搜索树。 OST具有Select(i)操作,类似于数组下标操作,您可以用相同的方法在索引0 ... N之间选择一个随机元素。

另一个选择是使用排序数组。可以使用sorted属性保留std::set的对数查找属性。

不幸的是,标准库既没有订单统计树,也没有排序数组集。

答案 1 :(得分:0)

std :: set的复杂度为o(log(n)),因此,不能降低仅使用std :: set的搜索复杂度。您可以使用像矢量这样的索引结构来实现这一目标。

此外,您无法使用以下代码实现随机搜索:

 std::random_device              rd;
 std::mt19937                    gen(rd());
 std::uniform_int_distribution<> dis( 0, set::size ( ) );

然后

 set::operator [] (dis(gen));

或令人反感的