std :: set插入成员函数的有效实现是什么?因为数据结构基于std :: less(运算符<需要为元素类型定义)对元素进行排序,所以在概念上很容易检测到重复。
它如何在内部实际运作?它是否使用了红背树数据结构(Josuttis一书中提到的实现细节)?
标准数据结构的实现可能会有所不同......
我有一个问题,我被迫有一个(一般来说)整数集应该是唯一的。集合的长度各不相同,因此我需要动态数据结构(基于我的狭隘知识,这会将内容缩小到列表,设置)。元素不一定需要排序,但可能没有重复。由于候选集总是有很多重复项(集很小,最多64个元素),因此尝试使用insert成员函数将重复项插入std :: set会导致与std :: list和其他算法相比产生大量开销可能不会诉诸于元素排序?
附加:输出集具有27个元素的固定大小。对不起,我忘了这个...这适用于特殊情况的问题。对于其他情况,长度是任意的(低于输入集)。
答案 0 :(得分:3)
如果您要同时创建整个集合,则可以尝试使用std::vector
来保存元素,std::sort
对其进行排序,并std::unique
删除重复项。
答案 1 :(得分:2)
std::set::insert
的复杂性为O(log n),或者如果使用“位置”插入并使位置正确,则摊销O(1)(参见例如http://cplusplus.com/reference/stl/set/insert/)。
底层机制依赖于实现。它通常是一棵红黑树,但这不是强制性的。您应该查看您喜欢的实现的源代码,以了解它正在做什么。
对于小型套装,有可能是由于空间局部性,对矢量的简单线性搜索将更便宜。但插入本身将需要复制以下所有元素。确切知道的唯一方法是分析每个选项。
答案 2 :(得分:2)
当你只提前知道64个可能的值时,只需取一个位字段并翻转实际看到的元素的位。这适用于n + O(1)步骤,你不能少于此。
插入大小为std::set
的m需要O(log(m))时间和比较,这意味着为此目的使用std::set
将花费O(n * log(n))和如果常数大于简单地对输入进行排序(这需要额外的空间)然后丢弃重复项,我不会感到惊讶。
使用std::list
执行相同的操作需要花费O(n ^ 2)的平均时间,因为在列表中查找插入位置需要O(n)。
一次将一个元素插入std::vector
也需要O(n ^ 2)个平均时间 - 在O(log(m))中找到插入位置是可行的,但是元素需要我移动到腾出空间。如果最终结果中的元素数量远小于输入,则下降到O(n * log(n)),几乎没有空间开销。
如果您有C ++ 11编译器或使用boost,您还可以使用哈希表。我不确定插入特性,但如果结果中的元素数量与输入大小相比较小,则只需要O(n)时间 - 与位字段不同,您不需要先验地知道结果的潜在元素或大小(虽然知道大小有帮助,因为你可以避免重复)。