在 std::map 和 std::unordered_map 之间进行选择

发布于 2024-09-26 13:18:12 字数 167 浏览 9 评论 0原文

现在 stdunordered_map 中有一个真正的哈希映射,为什么(或何时)我仍然想使用旧的 map 而不是 >unordered_map 在它实际存在的系统上?是否有任何我无法立即看到的明显情况?

Now that std has a real hash map in unordered_map, why (or when) would I still want to use the good old map over unordered_map on systems where it actually exists? Are there any obvious situations that I cannot immediately see?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

坠似风落 2024-10-03 13:18:12

正如已经提到的map允许以排序的方式迭代元素,但 unordered_map 不允许。这在许多情况下非常重要,例如显示集合(例如地址簿)。这也体现在其他间接方式中,例如:(1) 从 find() 返回的迭代器开始迭代,或 (2) 存在诸如 lower_bound() 之类的成员函数。

另外,我认为最坏情况搜索复杂性存在一些差异。

  • 对于 map 来说,时间复杂度为 O( lg N )

  • 对于 unordered_map< /code>,它是 O( N ) [当哈希函数不好导致太多哈希冲突时可能会发生这种情况。]

这同样适用于最坏情况 删除 复杂性。

As already mentioned, map allows to iterate over the elements in a sorted way, but unordered_map does not. This is very important in many situations, for example displaying a collection (e.g. address book). This also manifests in other indirect ways like: (1) Start iterating from the iterator returned by find(), or (2) existence of member functions like lower_bound().

Also, I think there is some difference in the worst case search complexity.

  • For map, it is O( lg N )

  • For unordered_map, it is O( N ) [This may happen when the hash function is not good leading to too many hash collisions.]

The same is applicable for worst case deletion complexity.

苏辞 2024-10-03 13:18:12

除了上面的答案之外,您还应该注意,仅仅因为 unordered_map 是恒定速度 (O(1)) 并不意味着它比 map< /code> (顺序log(N))。该常量可能大于 log(N),特别是因为 N 受 232(或 264)限制)。

因此,除了其他答案(map 维护顺序和哈希函数可能很困难)之外,map 的性能可能更高。

例如,在我为博客文章运行的程序中 我发现对于 VS10,std::unordered_mapstd::map 慢(尽管 boost::unordered_map 比两者都快)。

性能图

注意第 3 至第 5 个栏。

In addition to the answers above you should also note that just because unordered_map is constant speed (O(1)) doesn't mean that it's faster than map (of order log(N)). The constant may be bigger than log(N) especially since N is limited by 232 (or 264).

So in addition to the other answers (map maintains order and hash functions may be difficult) it may be that map is more performant.

For example in a program I ran for a blog post I saw that for VS10 std::unordered_map was slower than std::map (although boost::unordered_map was faster than both).

Performance Graph

Note 3rd through 5th bars.

大海や 2024-10-03 13:18:12

部分基于 Chandler Carruth 的 CppCon 2014 演讲

std::map (许多人认为)对于面向性能的工作没有用处:

  • 如果您想要 O(1) 摊销访问,请使用 正确的哈希映射(可能会使用开放寻址)。
  • 如果您想要 O(1) 摊销访问,但又懒得去实现任何东西,至少使用 std::unorderded_map 而不是 std::map 。
  • 如果您希望对地图进行排序顺序访问(通常不需要),请使用基于向量的内容。

另外,std::map 是一棵平衡树;你必须非常频繁地穿越它,或者重新平衡它。这些分别是缓存杀手和缓存启示录操作...所以只需对 std::map 说“不”。

您可能对关于高效哈希映射实现的这个SO问题感兴趣。

(PS - std::unordered_map 对缓存不友好,因为它使用链表作为存储桶。)

Partly based on Chandler Carruth's CppCon 2014 talk.

std::map is (considered by many to be) not useful for performance-oriented work:

  • If you want O(1)-amortized access, use a proper hash-map (which will probably use open addressing).
  • If you want O(1)-amortized access but can't be bothered to get a decent implementation of anything at least use std::unorderded_map rather than std::map.
  • If you want sorted sequential access into your map (which you typically don't), use something based on a vector.

Also, std::map is a balanced tree; and you have to traverse it, or re-balance it, incredibly often. These are cache-killer and cache-apocalypse operations respectively... so just say NO to std::map.

You might be interested in this SO question on efficient hash map implementations.

(PS - std::unordered_map is cache-unfriendly because it uses linked lists as buckets.)

薆情海 2024-10-03 13:18:12

我认为很明显,您需要使用 std::map 来按排序顺序迭代映射中的项目。

当您更愿意编写比较运算符(很直观)而不是哈希函数(通常非常不直观)时,也可以使用它。

I think it's obvious that you'd use the std::map you need to iterate across items in the map in sorted order.

You might also use it when you'd prefer to write a comparison operator (which is intuitive) instead of a hash function (which is generally very unintuitive).

似狗非友 2024-10-03 13:18:12

假设你有很大的钥匙,也许是很大的字符串。要为大字符串创建哈希值,您需要从头到尾遍历整个字符串。至少需要与密钥长度呈线性关系的时间。但是,当您仅使用键的 > 运算符搜索二叉树时,每个字符串比较都会在发现第一个不匹配时返回。对于大字符串来说,这通常是非常早的。

这个推理可以应用于std::unordered_mapstd::mapfind函数。如果键的性质导致生成哈希所需的时间(在 std::unordered_map 的情况下)比使用二分搜索查找元素的位置所需的时间(在情况下std::map),在 std::map 中查找键应该更快。很容易想到这种情况的场景,但我相信在实践中这种情况很少见。

Say you have very large keys, perhaps large strings. To create a hash value for a large string you need to go through the whole string from beginning to end. It will take at least linear time to the length of the key. However, when you only search a binary tree using the > operator of the key each string comparison can return when the first mismatch is found. This is typically very early for large strings.

This reasoning can be applied to the find function of std::unordered_map and std::map. If the nature of the key is such that it takes longer to produce a hash (in the case of std::unordered_map) than it takes to find the location of an element using binary search (in the case of std::map), it should be faster to lookup a key in the std::map. It's quite easy to think of scenarios where this would be the case, but they would be quite rare in practice i believe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文