对于操作计数()。 std::set<void*> 或 std::unordered_set<void*> 哪个更快?

Posted

技术标签:

【中文标题】对于操作计数()。 std::set<void*> 或 std::unordered_set<void*> 哪个更快?【英文标题】:For the operation count(). Which is faster std::set<void*> or std::unordered_set<void*>? 【发布时间】:2013-05-23 23:06:02 【问题描述】:

假设sizeof(void*) == sizeof(size_t) 并且散列指针只是将其转换为size_t。所以我想知道我的集合是否包含一个元素,哪个会更快std::set&lt;void*&gt;std::unordered_set&lt;void*&gt;

我知道std::set 的工作原理,但我不熟悉std::unordered_set。好吧,我知道无序集使用散列和桶,如果没有发生交集(这是我的情况),复杂性是 O(1)。但我不知道这种恒定的复杂性有多少。

如果容器中有多少日期是相关的,我的实际场景使用不到一百个¹。但我的好奇心涉及元素很少和元素很多的两种情况。

¹ 元素的数量非常少,即使是 std::vector 也能正常运行。

【问题讨论】:

哈希表倾向于使用更多内存在更短的时间内执行访问。 ***.com/questions/1349734/… 为什么不直接比较您感兴趣的操作的复杂性并据此决定呢?见unordered_setset,也许还有vector 该死,我忘了提出我的问题。我正在做的操作是检查一个元素是否包含在集合中。我刚刚编辑了它。 @syam 唯一重要的操作是 count()。它在集合上有复杂度 log(n),在 unordered_set 上有 1。我只是想知道这种恒定的复杂性有多大。让我强调一下,这不是我假装做的微优化,这只是我想知道的事情。 【参考方案1】:

我认为重要的一点在小脚注中:

元素的数量非常少,即使std::vector 也能正常运行。

std::vectorstd::setstd::unordered_set 对缓存更友好,因为它在内存的连续区域中分配其元素(这是标准规定的)。

尽管std::vector 的查找和插入复杂度比std::setstd::unordered_set 更差(线性与O(log N) 和摊销O(1) em>),数据局部性和更高的缓存命中率可能会主导计算复杂性并产生更好的性能。

总的来说,无论如何,您选择的数据结构对性能的影响还取决于您要对它们执行的操作类型及其频率 - 您的帖子中没有提到这一点。

不过,与往常一样,衡量不同的替代方案,然后再进行选择,并且当您没有证据表明它代表阻碍您的应用程序满足其性能要求的瓶颈时,始终支持更简单的设计.

【讨论】:

+1 表示“测量”——这是人们需要理解的。您可能要补充的一点是,如果插入很少并且查找频繁,则使用 std::binary_search 查找和插入内容可能是排序的 std::vector 的方法;通过这种方式,您可以获得 O(log n) 和缓存位置以进行查找和 O(n) 进行插入。 @cristicbz:好点。我认为您的评论是答案之后的第一个评论并获得了我的 +1,即使不编辑答案也会受到关注和考虑;)【参考方案2】:

unordered_set 在许多实现中比set 具有更好的缓存局部性。但是由于在您的情况下元素的数量非常少,vector 可能完全适合缓存,尽管查找元素的复杂度为 O(n),但它是一个更好的选择。

【讨论】:

以上是关于对于操作计数()。 std::set<void*> 或 std::unordered_set<void*> 哪个更快?的主要内容,如果未能解决你的问题,请参考以下文章

对于set iterator和const_iterator的输入,不能重载成员函数(但可以用于其他stl迭代器)

没有匹配函数调用‘std::set<unsigned int>::insert(std::size_t&)

插入 std::set<std::tuple<std::string, ...>> 时重复

std::multimap<key, value> 和 std::map<key, std::set<value> 有啥区别?

为啥 std::set::find 不提供提示迭代器?

std::set 唯一 ptr 范围插入