迭代有序与无序容器

时间:2015-07-21 08:33:31

标签: c++ c++11 unordered-map unordered-set stdset

我想知道哪些数据结构在std::setstd::mapstd::unordered_setstd::unordered_map之间迭代其元素更有效。

我搜索了SO,我找到了question。答案要么建议复制std::vector中的元素,要么使用Boost.Container,恕我直言不回答我的问题。

我的目的是在容器中保留大量独特的元素,大多数时候我想迭代它们。插入和提取更为罕见。我想避免将std::vectorstd::unique结合使用。

3 个答案:

答案 0 :(得分:3)

差异不在于订购或缺少一个,而是在支持容器中。如果它是一个连续的内存,由于迭代器的简单实现和缓存友好性,它应该快速迭代。

无序容器通常存储为向量(或类似的东西)的向量,而有序容器是使用树实现的,但它毕竟留待实现。这表明迭代无序版本应该是浪费。然而,这毕竟留给了实现,我看到了具有不同行为的实现(这使得规则有点公平)。

一般来说,容器性能是一个相当复杂的主题,通常需要在实际应用中进行测试才能获得可靠的答案。实施定义的内容可能会影响性能。如果我不得不盲目进去,我会去hash_set。复制到vector也可能是一个不错的选择。

编辑:正如@TonyD在评论中所说,有一条规则,在不超过max_load_factor()时,在添加元素期间不允许使迭代器无效,这实际上排除了在内存中连续的支持容器。 / p>

因此,将所有内容复制到向量中似乎是更合理的选择。如果您需要删除重复项,可行的选项可能是使用http://en.cppreference.com/w/cpp/algorithm/sort并且很容易忽略dupe。我听说使用vectorsort来排序数组(或向量)通常是一个常用的选项,以便需要一个需要进行分类并且经常迭代的容器而不是修改。

答案 1 :(得分:3)

让我们考虑set vs unordered_set

这里的主要区别在于迭代的“本质”,即遍历集合将按顺序为您提供元素,而遍历无序集合中的范围将为您提供一系列无特定顺序的值。

假设您想要遍历范围[it1, it2]。如果我们排除查找元素it1和it2所需的查找时间,则不能从一个案例直接映射到另一个案例,因为即使您使用相同的元素来构造容器,其间的元素也不会保持相同。

有些情况下,例如此类内容具有含义您想要遍历固定数量的元素(无论它们是什么)或何时需要遍历整个容器。在这种情况下,您需要考虑实施机制

集合通常像红黑树(一种二叉搜索树)一样实现。像所有二叉搜索树一样,它们允许有效的有序遍历(LRR:左右根)。那就是遍历你支付指针追逐的成本(就像遍历列表一样)。

typical red black tree layout

另一方面,无序集是哈希表,而对于我的knowledge,STL实现使用带链接的哈希。这意味着(在非常高的级别),用于结构的是一个(连续的)缓冲区,其中每个元素是包含元素的链(列表)的头部。元素在这些链(桶)和缓冲区之间的布局方式将影响遍历时间,但是这次你将再次追逐指针再次跳过不同的列表。我不认为它会因树木情况而有很大差异,但肯定不会更好。

schematic layout of hashing with chaining

无论如何,微调和基准测试将为您的特定应用提供答案。

答案 2 :(得分:0)

从最快到最慢的迭代应该是:set>地图> unordered_set> unordered_map; set比map小一点,并且它们以二叉树规则排序,因此应该比无序容器更快。