【发布时间】:2011-04-23 14:11:32
【问题描述】:
既然std 在unordered_map 中有一个真正的哈希映射,为什么(或何时)我仍想在实际存在的系统上使用旧的map 而不是unordered_map?有没有我无法立即看到的明显情况?
【问题讨论】:
标签: c++ c++11 hash map unordered-map
既然std 在unordered_map 中有一个真正的哈希映射,为什么(或何时)我仍想在实际存在的系统上使用旧的map 而不是unordered_map?有没有我无法立即看到的明显情况?
【问题讨论】:
标签: c++ c++11 hash map unordered-map
作为already mentioned,map 允许以排序方式遍历元素,但unordered_map 不允许。这在许多情况下都非常重要,例如显示集合(例如地址簿)。这也体现在其他间接方式中,例如:(1) 从 find() 返回的迭代器开始迭代,或 (2) 存在像 lower_bound() 这样的成员函数。
另外,我认为最坏情况 搜索的复杂性有所不同。
对于map,是O(lg N)
对于unordered_map,为 O( N ) [这可能发生在散列函数不好导致太多散列冲突时。]
这同样适用于最坏情况 删除复杂性。
【讨论】:
除了上面的答案,您还应该注意,仅仅因为unordered_map 是恒定速度(O(1))并不意味着它比map(顺序为log(N))快。该常数可能大于log(N),尤其是因为N 受232(或264)的限制。
因此,除了其他答案(map 维护顺序和哈希函数可能很困难)之外,map 的性能可能更高。
例如,在我为blog post 运行的程序中,我发现对于VS10,std::unordered_map 比std::map 慢(尽管boost::unordered_map 比两者都快)。
注意第 3 到第 5 小节。
【讨论】:
N=10,000,000 中所说的那样。
这要归功于 Google 的 Chandler Carruth 在他的CppCon 2014 lecture
std::map(很多人认为)对于面向性能的工作没有用处:如果您想要 O(1) 分期访问,请使用适当的关联数组(或者如果缺少关联数组,std::unorderded_map);如果您想要排序的顺序访问,请使用基于向量的东西。
另外,std::map 是一棵平衡树;你必须非常频繁地遍历它,或者重新平衡它。这些分别是缓存杀手和缓存启示录操作……所以对std::map说不。
您可能对this SO question 感兴趣,了解高效的哈希映射实现。
(PS - std::unordered_map 对缓存不友好,因为它使用链表作为存储桶。)
【讨论】:
我认为很明显你会使用std::map,你需要按排序顺序遍历地图中的项目。
当您更喜欢编写比较运算符(直观)而不是哈希函数(通常非常不直观)时,您也可以使用它。
【讨论】:
假设您有非常大的键,可能是大字符串。要为大字符串创建哈希值,您需要从头到尾遍历整个字符串。密钥的长度至少需要线性时间。但是,当您仅使用键的 > 运算符搜索二叉树时,每个字符串比较都可以在找到第一个不匹配时返回。对于大字符串来说,这通常很早。
这个推理可以应用于std::unordered_map和std::map的find函数。如果密钥的性质是生成哈希(在std::unordered_map 的情况下)比使用二分搜索找到元素的位置(在std::map 的情况下)需要更长的时间,它应该更快地在std::map 中查找键。很容易想到会出现这种情况的场景,但我相信在实践中这种情况非常罕见。
【讨论】: