迭代有序容器与无序容器
iterate ordered versus unordered containers
我想知道在 std::set
、std::map
和 std::unordered_set
、std::unordered_map
.[=19= 之间迭代其元素时哪些数据结构更有效]
我搜索了 SO 并找到了这个 question。答案建议复制 std::vector
中的元素或使用 Boost.Container
,恕我直言,这不会回答我的问题。
我的目的是在容器中保存大量独特的元素,大多数时候我想遍历它们。插入和提取更为罕见。我想避免 std::vector
与 std::unique
.
结合使用
区别不在于订购或缺少一个,而在于后备容器。如果它是一个连续的内存,由于迭代器的简单实现和缓存友好性,它应该可以快速迭代。
无序容器通常存储为向量的向量(或类似的东西),而有序容器是使用树实现的,但毕竟是留给实现的。这表明迭代无序版本应该是浪费。然而,这毕竟留给了实施,我看到了具有不同行为的实施(为了公平起见,稍微改变了规则)。
总的来说,容器性能是一个比较复杂的话题,通常需要在实际应用中进行测试才能得到可靠的答案。有很多可能影响性能的实现定义的东西。如果我必须盲目进入,我会选择 hash_set
。复制到 vector
可能也是一个不错的选择。
编辑:正如@TonyD 在其评论中所说,有一条规则,即在不超过 max_load_factor()
时不允许在添加元素期间使迭代器无效,这实际上排除了内存中连续的后备容器.
因此,将所有内容复制到向量中似乎是更合理的选择。如果您需要删除重复项,一个可行的选择可能是使用 http://en.cppreference.com/w/cpp/algorithm/sort
并且很容易忽略重复项。我听说使用 vector
和 sort
来排序数组(或向量)是一个经常使用的选项,以防需要一个需要排序的容器并且被更频繁地迭代比修改。
让我们考虑 set
与 unordered_set
。
这里的主要区别是迭代的 'nature',即遍历集合会给你有序的元素,而遍历无序集合中的范围会给你一堆值没有特别的顺序。
假设您要遍历范围 [it1, it2]
。如果我们排除查找元素 it1 和 it2 所需的查找时间,则无法从一种情况直接映射到另一种情况,因为即使您使用相同的元素构造容器,也不能保证两者之间的元素相同.
但是在某些情况下,这样的事情是有意义的,例如你想遍历固定数量的元素(不管它们是什么)或者当你需要遍历整个容器时。在这种情况下,您需要考虑 实施机制 :
集合的实现方式通常类似于红黑树(二叉搜索树的一种形式)。像所有二叉搜索树一样,允许对其元素进行高效的有序遍历(LRR:左根右)。那就是遍历你付出指针追逐的代价(就像遍历一个列表)。
另一方面,无序集是哈希表,对我来说 knowledge STL 实现使用带链接的哈希。这意味着(在非常高的层次上)用于结构的是一个(连续的)缓冲区,其中每个元素都是包含元素的链(列表)的头部。元素在这些链(桶)和缓冲区中的布局方式将影响遍历时间,但是这次您将再次追逐指针,跳过不同的列表。我不认为它会与树的情况有很大的不同,但肯定不会更好。
在任何情况下,微调和基准测试都会为您的特定应用程序提供答案。
从最快到最慢的迭代应该是:set > map > unordered_set > unordered_map;
set 比 map 轻一点,而且它们是用二叉树规则排序的,所以应该比 unordered_ 容器快。
我想知道在 std::set
、std::map
和 std::unordered_set
、std::unordered_map
.[=19= 之间迭代其元素时哪些数据结构更有效]
我搜索了 SO 并找到了这个 question。答案建议复制 std::vector
中的元素或使用 Boost.Container
,恕我直言,这不会回答我的问题。
我的目的是在容器中保存大量独特的元素,大多数时候我想遍历它们。插入和提取更为罕见。我想避免 std::vector
与 std::unique
.
区别不在于订购或缺少一个,而在于后备容器。如果它是一个连续的内存,由于迭代器的简单实现和缓存友好性,它应该可以快速迭代。
无序容器通常存储为向量的向量(或类似的东西),而有序容器是使用树实现的,但毕竟是留给实现的。这表明迭代无序版本应该是浪费。然而,这毕竟留给了实施,我看到了具有不同行为的实施(为了公平起见,稍微改变了规则)。
总的来说,容器性能是一个比较复杂的话题,通常需要在实际应用中进行测试才能得到可靠的答案。有很多可能影响性能的实现定义的东西。如果我必须盲目进入,我会选择 hash_set
。复制到 vector
可能也是一个不错的选择。
编辑:正如@TonyD 在其评论中所说,有一条规则,即在不超过 max_load_factor()
时不允许在添加元素期间使迭代器无效,这实际上排除了内存中连续的后备容器.
因此,将所有内容复制到向量中似乎是更合理的选择。如果您需要删除重复项,一个可行的选择可能是使用 http://en.cppreference.com/w/cpp/algorithm/sort
并且很容易忽略重复项。我听说使用 vector
和 sort
来排序数组(或向量)是一个经常使用的选项,以防需要一个需要排序的容器并且被更频繁地迭代比修改。
让我们考虑 set
与 unordered_set
。
这里的主要区别是迭代的 'nature',即遍历集合会给你有序的元素,而遍历无序集合中的范围会给你一堆值没有特别的顺序。
假设您要遍历范围 [it1, it2]
。如果我们排除查找元素 it1 和 it2 所需的查找时间,则无法从一种情况直接映射到另一种情况,因为即使您使用相同的元素构造容器,也不能保证两者之间的元素相同.
但是在某些情况下,这样的事情是有意义的,例如你想遍历固定数量的元素(不管它们是什么)或者当你需要遍历整个容器时。在这种情况下,您需要考虑 实施机制 :
集合的实现方式通常类似于红黑树(二叉搜索树的一种形式)。像所有二叉搜索树一样,允许对其元素进行高效的有序遍历(LRR:左根右)。那就是遍历你付出指针追逐的代价(就像遍历一个列表)。
另一方面,无序集是哈希表,对我来说 knowledge STL 实现使用带链接的哈希。这意味着(在非常高的层次上)用于结构的是一个(连续的)缓冲区,其中每个元素都是包含元素的链(列表)的头部。元素在这些链(桶)和缓冲区中的布局方式将影响遍历时间,但是这次您将再次追逐指针,跳过不同的列表。我不认为它会与树的情况有很大的不同,但肯定不会更好。
在任何情况下,微调和基准测试都会为您的特定应用程序提供答案。
从最快到最慢的迭代应该是:set > map > unordered_set > unordered_map; set 比 map 轻一点,而且它们是用二叉树规则排序的,所以应该比 unordered_ 容器快。