在 c + + unordered_map最近谈论让我认识到,对于大多数我使用map之前,由于 ( O (日志 n)分摊的 o (1) ) 的查找的效率的情况下,应该使用unordered_map大多数时间我使用一个映射,使用任何一个int的或作为关键字std::strings ,因此我使用了哈希函数的定义没有问题。我越想过它,我就越意识到找不到任何原因的通过unordered_map使用std::map的简单类型时 — 我花了接口,一看,没有发现任何明显的差异,会影响我的代码。

因此,问题-有unordered map在简单的类型,如intstd::string的情况下通过使用std::map任何真正的理由?

我想问一下从严格编程的角度看--我知道,它没有完全被视为标准,而且它可能会带来与移植问题。

此外预期一个正确的答案可能是"更高的数据集较小是"由于较小的开销 (这真是吗?),因此我想要限制的密钥量微不足道的情况下将问题 (> 1 024)。

编辑︰真是痛苦,我忘记了明显 (谢谢 GMan !)-是的我知道这一点,并正在寻找其他原因当然 — 排序图的。

2010-02-04 02:37:43
问题评论:

我喜欢要求面试中的回答这个问题:"当是快速排序好冒泡排序比?"问题的答案提供了深入了解的复杂性理论的实际应用,不只是纯黑色和白色的语句如 o (1) 优于 o (n) 或 O(k) 相当于 O(logn) 等...

认为您是 @Beh,"当优于快速排序时冒泡排序": P

智能指针是一个微不足道的密钥?

回答:

别忘了map的保持有序的元素。如果不能放弃的显然不能使用unordered_map.

其他需要注意的是, unordered_map通常使用更多内存。map只具有几个房子保持指针则为每个对象的内存。Contrarily, unordered_map很大数组 (它们会让某些实现中很大),然后更多的内存,每个对象。如果您需要了解内存,map应证明更好,因为它缺少大型数组。

因此,如果您需要纯查阅检索,我想说unordered_map是转的办法。但总有利弊,并在您无法承受这些,则无法使用它。

只是从个人的经验,我发现一个巨大的改进性能 (当然计) 使用unordered_map而不在主实体查找表map时。

另一方面,我发现它是在反复插入和删除元素要慢得多。它非常适合于相对静态元素的集合,但如果要做的插入和删除操作的哈希 + bucketing 吨似乎会增加。(注意,这是对多个小版本)。

+ 1︰ 是的忘记了明显有序属性:),且内存提示是我不知道-感谢

更多一点有关与映射 (或向量与列表) 的 unordered_map 的 large(r) 内存块属性,默认进程堆 (此处交谈窗口) 进行序列化。在多线程应用程序中的大笔资金的分配 (小) 块是非常昂贵的。

RA︰ 可以一定程度上控制,与自己与任何容器,相结合的分配器类型如果您认为重要的任何特定程序。

如果您知道unordered_map的大小和保留由开始时的做您仍然支付许多插入损失?说,你只有一次插入时生成查找表中-,然后只能读取它。

@thomthom 就可以判断,应在性能方面的任何损失。性能所需一次点击的原因是由于这样一个事实︰ 如果数组占用太多,它将进行的所有元素的改头换面而已。如果调用储备,它可能会重复现有的元素,但如果您在开始时调用它,然后应该有任何损失,至少根据cplusplus.com/reference/unordered_map/unordered_map/reserve

如果您想要比较 std::map 和 std::unordered_map 实现的速度,您可以使用 Google 的sparsehash项目的 time_hash_map 程序来它们的时间。例如,对于 gcc 4.4.2 x86_64 Linux 系统上

$ ./time_hash_map
TR1 UNORDERED_MAP (4 byte objects, 10000000 iterations):
map_grow              126.1 ns  (27427396 hashes, 40000000 copies)  290.9 MB
map_predict/grow       67.4 ns  (10000000 hashes, 40000000 copies)  232.8 MB
map_replace            22.3 ns  (37427396 hashes, 40000000 copies)
map_fetch              16.3 ns  (37427396 hashes, 40000000 copies)
map_fetch_empty         9.8 ns  (10000000 hashes,        0 copies)
map_remove             49.1 ns  (37427396 hashes, 40000000 copies)
map_toggle             86.1 ns  (20000000 hashes, 40000000 copies)

STANDARD MAP (4 byte objects, 10000000 iterations):
map_grow              225.3 ns  (       0 hashes, 20000000 copies)  462.4 MB
map_predict/grow      225.1 ns  (       0 hashes, 20000000 copies)  462.6 MB
map_replace           151.2 ns  (       0 hashes, 20000000 copies)
map_fetch             156.0 ns  (       0 hashes, 20000000 copies)
map_fetch_empty         1.4 ns  (       0 hashes,        0 copies)
map_remove            141.0 ns  (       0 hashes, 20000000 copies)
map_toggle             67.3 ns  (       0 hashes, 20000000 copies)

我会大致回显所做的相同点 GMan︰ 根据使用的类型, std::map可以是 (并且通常是) 比std::tr1::unordered_map (使用 VS 2008 SP1 中包含的实现)。

还有一些并发的因素需要注意。例如,在std::map,您进行比较键,这意味着只看一下足够多的键来区分左右子分支的树的开始。我的经验,几乎只有看整个键时如果您正使用 int,则可以在一条指令进行比较类似。与更常见的密钥类型,如 std::string,通常比较只有几个字符左右。

不错的哈希函数,相反,总是关注整个键。IOW,即使表查找是恒定的复杂性,希本身有近似线性复杂性 (尽管在长度的密钥,而不是数项)。长字符串作为键, std::map可能unordered_map者甚至开始搜索之前完成搜索。

第二,有很多种方法来调整哈希表的大小,大多数都非常慢--,除非查找大大多于插入和删除,std::map 通常会比std::unordered_map更快点.

当然,如我上一个问题中提到的注释中,您可以使用目录树。这都有优点和缺点。一方面,它限制了对该树的最坏情况。它还允许快速插入和删除操作,因为 (至少当我已经完成它) 我使用固定大小的表。消除了所有表调整大小都允许您保持哈希表,很多更简单和通常更快。

编辑︰ 天哪,我差点忘记了还要其他的一点︰ 哈希和基于树映射的要求都不同。哈希显然需要的哈希函数和相等性比较,其中有序的映射需要较少的比较。当然我提到混合需要两者。当然,通用用例的使用一个字符串作为键,这真的不是问题,但一些类型的密钥适合于哈希处理 (或相反) 更好地排序。

+ 1︰ 较长的字符串的哈希调整大小和渴望字符串比较是非常有效的点

散列大小调整可以被消除下通过dynamic hashing技术,其中包括让过渡期在每次插入一个项目,您还再重复k其他项目。当然,这意味着,在转换过程中您需要搜索两个不同表...

"与作为键的长字符串,std::map 可能完成搜索之前 unordered_map 甚至开始其搜索。"— 如果该项不存在于该集合。如果存在那么当然全长需要进行比较以确认相匹配。但是unordered_map同样需要确认哈希匹配与完全比较,因此这完全取决于您对比查找过程的哪些部分。

通常,您可以替换基于知识的数据的哈希函数。例如,如果您长字符串改变更是在最后的 20 字节比前 100,只是的哈希在最后 20 个。

我是从 @Jerry 棺材,建议,有序的映射会出现长字符串的性能提高 (它可以从pastebin) 经过试验后,我发现这只似乎成立的随机字符串,集合时地图初始化 (它包含单词的大量前缀重叠) 的已排序字典与答案的那里此规则将拆,大概是由于增加的树深度检索值所需。结果如下所示,第一个数字列插入时间,二是提取时间。

g++ -g -O3 --std=c++0x   -c -o stdtests.o stdtests.cpp
g++ -o stdtests stdtests.o
gmurphy@interloper:HashTests$ ./stdtests
# 1st number column is insert time, 2nd is fetch time
 ** Integer Keys ** 
 unordered:      137      15
   ordered:      168      81
 ** Random String Keys ** 
 unordered:       55      50
   ordered:       33      31
 ** Real Words Keys ** 
 unordered:      278      76
   ordered:      516     298

我只会点出,...有许多种类型的unordered_maps。

散列映射上的维基百科文章中查找。具体使用哪一种实现,取决于中术语的查找、 插入和删除的特征很明显可能有所不同。

这是什么照管我最大,增加了unordered_map于 STL︰ 他们将不得不选择特定的实现,我怀疑它们成因Policy,接下来,因此,我们将坚持实现平均使用和任何其他情况下...

例如一些哈希映射具有线性 rehashing,其中而不是在一次 rehashing 整个哈希映射,一部分在每次插入,这有助于摊销成本的改头换面而已。

另一个例子︰ 一些哈希映射节点的简单列表用于存储桶、 其他人使用地图、 其他人不使用节点而找到的最接近段和最后部分将使用的节点的列表,但重新排列它以便访问过的最后一个元素是在前面 (如缓存的事)。

所以此刻我往往更喜欢std::map或可能是loki::AssocVector (对于冻结数据集)。

别让我打开错误,想要使用std::unordered_map和我可能在将来,但很难"信任"这种容器的可移植性在您认为所有的方式实现它,并且各种成绩该操作的结果。

+ 1︰ 有效的点-生命更加方便时我使用的我自己的实现,至少我知道它很糟糕︰ >

请输入您的翻译

Is there any advantage of using map over unordered_map in case of trivial keys?

确认取消