我正在阅读尼古拉·约苏蒂斯(Nicolai Josuttis(的《标准图书馆》(The Standard Library(,第二版。在其第 183 页中,我们有:
我使用无序地图和多重地图的示例
第 179 页上为多重地图提供的示例也适用于 无序多重映射(如果将
map
替换为unordered_map
包括指令和multimap
byunordered_multimap
集装箱声明:#include <unordered_map> ... unordered_multimap<int,string> coll; ...
唯一的区别是元素的顺序是未定义的。 但是,在大多数平台上,元素仍将被排序,因为作为默认哈希函数,使用模运算符。
用粗体强调了我不清楚的部分。当我读到这篇文章时,我的第一印象是作者说两个程序(第 179 页的那个,见下文(和上面的一个(应该在大多数平台上以相同的顺序打印城市名称。但这不会发生在 clang 和 GCC 中。查看 GCC 中map
和unordered_map
的实时示例。在叮当声中获得了相同的结果。
想了一会儿后,我将作者解释为,当用unordered_map
处理时,几乎所有平台的城市名称都以相同的顺序打印,输出似乎证实了这一点。但即便如此,我也很难接受这种解释,因为不同的实现可能会使用不同的哈希函数!
下面,您将在上面提到的第 179 页中找到示例:
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
multimap<int,string> coll; // container for int/string values
// insert some elements in arbitrary order
// - a value with key 1 gets inserted twice
coll = { {5,"tagged"},
{2,"a"},
{1,"this"},
{4,"of"},
{6,"strings"},
{1,"is"},
{3,"multimap"} };
// print all element values
// - element member second is the value
for (auto elem : coll) {
cout << elem.second << ’ ’;
}
cout << endl;
}
我认为这充其量是无益的。
int
常见的默认哈希函数是使用int
本身而不进行更改。因此,如果哈希表的存储桶多于最大整数,并且重复项的添加顺序相同,则大多数实现将(意外地(按排序顺序输出对。
然而,一般来说,对于具有一些排序的对象,如果 A <B.H(.(><H(B(><= 存储桶计数的情况。
因此,这本书实际上是指出了一个相当人为的特殊情况的特征。为什么我认为这没有帮助?呈现人为特殊情况的偶然属性可能会意外地导致读者认为它们是某些更广泛功能的示例。
哈希映射中的条目不会以任何有用的顺序返回。它们不会按广告顺序返回。它们不会以相反的广告顺序返回。它们不会按排序顺序返回。他们不会以任何顺序回来。[山姆我是]。
如果一个例子是值得的,那将是他们没有按顺序返回的示例。
我认为混淆来自我们正在谈论 2 个哈希函数的事实。
第一个是从键中获取数字的函数。默认情况下,这是 std::hash,但也可以作为参数提供给 std::unorderded_map
。
存储桶索引的函数,即获取此数字并返回范围0 - bucket_count() - 1
中的数字。这个是实现定义的,但它几乎总是模%
因为它是最简单的,如果原始哈希函数是均匀分布的,则不会产生负面影响,std::hash
是和用户定义的应该是。
这种说法是无稽之谈。在某些平台上,在特定情况下,元素在(通常很小的(unordered_multimap
中的顺序将与multimap
中的顺序相同。但是,对程序员真正有用的是保证,例如"此容器已排序"。这既不能保证unordered_(multi)map
也不能保证unordered_(multi)set
.支持等效键(使用标准中的术语(的无序关联容器的一个真正有用的排序保证是,具有等效键的条目总是相邻的,例如AACBBBD或BBBAADC是有效订单,但ABACBBD不是。这就是这些容器像它们的分类表亲一样支持equal_range
操作的原因。即便如此(在 C++11 中(,multimap
对这些条目也有更强的保证,因为它们不仅相邻,而且按插入顺序出现,unordered_multimap
可能并非如此。实际上,出于性能原因,它们可能会以相反的插入顺序出现。但也不要依赖它...