新标准定义了4个无序关联容器,这些容器不是使用比较运算符来组织元素,而是使用哈希函数和关键字类型的 ==
运算符。
如果关键字类型固定就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器。
使用无序容器
通常可以使用一个无序容器替换对应的有序容器,反之亦然。但是,由于元素未按顺序存储,一个使用无序容器的程序的输出通常会与使用有序容器的版本不同。
unordered_map<string, size_t> word_count;
string word;
while (cin >> word)
++word_count[word];
for (const auto &w : word_count)
cout << w.first << " occurs " << w.second << ((w.second > 1) ? " times" : " time") << endl;
管理桶
无序容器在存储上组织为一组桶,每个桶保存零个或多个元素。无序容器使用一个哈希函数将元素映射到桶。为了访问一个元素,容器首先计算元素的哈希值,它指出应该搜索哪个桶。容器将具有一个特定哈希值的所有元素都保存在相同的桶中,如果容器允许重复关键字,则具有相同关键字的元素也在一个桶中。因此,无序容器的性能依赖于哈希函数的质量和桶的数量和大小。
无序容器提供了一组管理桶的函数,这些成员 函数允许我们查询容器的状态以及在必要时强制容器进行重组。
无序容器对关键字类型的要求
默认情况下,无序容器使用关键字类型的 == 运算符来比较元素,它们还使用一个 hash<key_type>
类型的对象来生成每个元素的哈希值。标准库为内置类型(包含指针)提供了hash模板,还为一些标准库类型,包含 string
和智能指针类型定义了 hash
。因此,可以直接定义关键字是内置类型(包含指针类型)、string
、智能指针类型的无序容器。
不能直接定义关键字类型为自定义类型的无序容器,不能直接使用哈希模板,必须提供自定义的 hash
模板。
为了能将 Sales_data
用作关键字,要提供函数来代替 ==
运算符和哈希值计算函数:
size_t hasher(const Sales_data &sd)
{
return hash<string>()(sd.isbn());
}
bool eqOp(const Sales_data *lhs,const Sales_data *rhs)
{
return lhs.isbn() == rhs.isbn();
}
//定义一个 unordered_multiset:
using SD_multiset = unordered_multiset<Sales_data,decltype(hasher)*,decltype(eqOp)*>;
SD_multiset bookStore(42,hasher,eqOp);