我的数据是一组有序的整数
[0] = 12345 [1] = 12346 [2] = 12454 等
我需要检查一个值是否在C ++集合中,哪个容器在检索时具有最低的复杂度?在这种情况下,数据在初始化后不会增长。在C#中我会使用字典,在c ++中,我可以使用hash_map或set。如果数据是无序的,我会使用boost的无序集合。但是,自订购数据以来,我有更好的选择吗?感谢
编辑:集合的大小是几百件
答案 0 :(得分:4)
如果数据位于有序的随机访问容器中(例如std::vector
,std::deque
或普通数组),那么std::binary_search
将在对数时间内查找值是否存在。如果您需要找到它的位置,请使用std::lower_bound
(也是对数)。
答案 1 :(得分:4)
只是详细了解已经说过的内容。
已分类的容器
这里的不变性非常重要:std::map
和std::set
通常用二叉树(我的STL的几个版本的红黑树)实现,因为插入,检索的要求和删除操作(特别是因为迭代器要求无效)。
然而,由于不变性,你怀疑还有其他候选人,其中最重要的是阵列式容器。他们在这里有一些优势:
这里有几个“随机存取容器”:
Boost.Array
std::vector
std::deque
所以你真正需要做的唯一事情就是分两步完成:
std::sort
。std::binary_search
搜索值,其中包含O(log(n))复杂度由于缓存局部性,即使渐近行为相似,搜索实际上也会更快。
如果您不想重新发明轮子,您还可以查看Alexandrescu的[AssocVector][1]
。 Alexandrescu基本上将std::set
和std::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_map和boost::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::set
或std::map
之类的内容是没有意义的,因为这些优先于二进制搜索没有优势,因为匹配的数字列表在初始化后不会改变。
因此,问题是n的近似值,以及您打算探测表的次数。如果您不打算检查多个值以查看它们是否在提供的整数中,那么设置时间非常重要,并且排序容器上的std::binary_search
是可行的方法。如果要检查很多值,可能需要设置哈希表。如果n很大,那么哈希表的探测速度比二进制搜索快,如果有很多探测,这就是主要成本。
因此,如果要比较的整数数量相当小,或者探测值的数量很小,请使用二进制搜索。如果int的数量很大,并且探测数量很大,请使用哈希表。