用于检查有序数据是否在集合中的c ++容器

时间:2010-01-20 17:31:11

标签: c++ collections

我的数据是一组有序的整数

[0] = 12345 [1] = 12346 [2] = 12454 等

我需要检查一个值是否在C ++集合中,哪个容器在检索时具有最低的复杂度?在这种情况下,数据在初始化后不会增长。在C#中我会使用字典,在c ++中,我可以使用hash_map或set。如果数据是无序的,我会使用boost的无序集合。但是,自订购数据以来,我有更好的选择吗?感谢

编辑:集合的大小是几百件

5 个答案:

答案 0 :(得分:4)

如果数据位于有序的随机访问容器中(例如std::vectorstd::deque或普通数组),那么std::binary_search将在对数时间内查找值是否存在。如果您需要找到它的位置,请使用std::lower_bound(也是对数)。

答案 1 :(得分:4)

只是详细了解已经说过的内容。

已分类的容器

这里的不变性非常重要:std::mapstd::set通常用二叉树(我的STL的几个版本的红黑树)实现,因为插入,检索的要求和删除操作(特别是因为迭代器要求无效)。

然而,由于不变性,你怀疑还有其他候选人,其中最重要的是阵列式容器。他们在这里有一些优势:

  • 最小开销(以记忆为单位)
  • 内存的连续性,从而缓存局部性

这里有几个“随机存取容器”:

  • Boost.Array
  • std::vector
  • std::deque

所以你真正需要做的唯一事情就是分两步完成:

  • 将所有值推送到您选择的容器中,然后(在插入所有容器后)使用std::sort
  • 使用std::binary_search搜索值,其中包含O(log(n))复杂度

由于缓存局部性,即使渐近行为相似,搜索实际上也会更快。

如果您不想重新发明轮子,您还可以查看Alexandrescu的[AssocVector][1]。 Alexandrescu基本上将std::setstd::map接口移到std::vector上:

  • 因为小数据集的速度更快
  • 因为冻结数据集可能更快

未分类的容器

实际上,如果你真的不关心秩序而且你的收藏有点大,那么unordered_set会更快,特别是因为整数对于散列size_t hash_method(int i) { return i; }是如此微不足道。

这可以很好地工作......除非你遇到一个以某种方式导致大量冲突的集合,因为那时未分类的容器将在线性时间内搜索给定散列的“碰撞”列表。

<强>结论

只需尝试排序 std::vector方法和boost::unordered_set方法以及“真实”数据集(以及所有优化)并选择最适合您的方法。< / p>

不幸的是我们真的无法帮助更多,因为它在很大程度上取决于数据集的大小及其元素的重新分配

答案 2 :(得分:3)

使用sort ed std::vector,然后使用std::binary_search进行搜索。

您的其他选项将是hash_map(不是在C ++标准中尚未,但还有其他选项,例如SGI's hash_mapboost::unordered_map)或{{3} }。

如果您从未添加到您的收藏中,带有binary_search的排序向量很可能比地图具有更好的性能。

答案 3 :(得分:2)

我建议使用std :: vector&lt; int&gt;存储它们和std :: binary_search或std :: lower_bound来检索它们。

std :: unordered_set和std :: set都会增加显着的内存开销 - 即使unordered_set提供O(1)查找,O(logn)二进制搜索也可能会超出它,因为数据是连续存储的(否)指针跟随,页面错误的可能性较小等)并且您不需要计算散列函数。

答案 4 :(得分:1)

如果您已经拥有有序数组或std::vector<int>或类似的数据容器,则可以使用std::binary_search来探测每个值。没有设置时间,但每个探测将花费O(log n)时间,其中n是您已经获得的有序int数。

或者,您可以使用某种哈希,例如boost::unordered_set<int>。这需要一些时间来设置,并且可能需要更多空间,但每个探测平均需要O(1)时间。 (对于小n,这个O(1)可能比之前的O(log n)更多。当然,对于小n,无论如何时间都可以忽略不计。)

查看std::setstd::map之类的内容是没有意义的,因为这些优先于二进制搜索没有优势,因为匹配的数字列表在初始化后不会改变。

因此,问题是n的近似值,以及您打算探测表的次数。如果您不打算检查多个值以查看它们是否在提供的整数中,那么设置时间非常重要,并且排序容器上的std::binary_search是可行的方法。如果要检查很多值,可能需要设置哈希表。如果n很大,那么哈希表的探测速度比二进制搜索快,如果有很多探测,这就是主要成本。

因此,如果要比较的整数数量相当小,或者探测值的数量很小,请使用二进制搜索。如果int的数量很大,并且探测数量很大,请使用哈希表。