《C++Primer》第十一章 关联容器

2020-11-19  本文已影响0人  TOMOCAT

简介

标准库提供8个关联容器:

1. 定义关联容器

可以通过列表初始化的方式定义map或者set

set<string> exclude = {"the", "but", "and", "or", "an", "a"};
map<string, string> authors = { {"Joyce", "James"}, {"Austen", "Jane"}, "Dickens", "Charles" }

2. 关键字类型的要求

对于有序容器,关键字类型必须定义元素比较的方法。默认情况下,标准库使用关键字类型的<运算符来比较两个关键字。

3. pair类型

pair定义在头文件utility中,保存两个数据成员:

pair<string, size_t> word_count;

pair的数据成员是public的,两个成员分别被命名为firstseconndpair的操作包括:

关联容器操作

C++中用下面这些类型表示容器关键字和值的类型:

1. 关联容器迭代器

当解引用一个关联容器迭代器时,我们会得到一个类型为容器的value_type的值:

使用迭代器可以遍历map

auto map_it = word_count.cbegin();

while (map_it != word_count.cend()) {
    cout << map_it->first << " occurs "
         << map_it->second << " times" << endl;
    ++map_it; // 递增迭代器, 移动到下一个元素
}

注意我们通常不对关联容器使用泛型算法,一方面是因为关键字是const这一特性意味着我们不能将关联容器传递给修改或者重排容器元素的算法;另一方面虽然关联容器可用于只读取元素的算法,但是这类算法很多都需要搜索序列,由于关联容器不支持通过关键字进行快速查找,因此使用泛型搜索算法几乎总是一个坏主意。

在实际编程中,如果我们真的要对一个关联容器使用算法,要么是将它当做一个源序列,要么当做一个目的位置。比如使用copy算法将元素从一个关联容器拷贝到另一个序列,类似的可以用inserter将一个插入器绑定到一个关联容器从而将关联容器作为一个目的位置来调用另一个算法。

2. 添加元素

// set
vector<int> ivec = {2, 4, 6, 8, 2, 4, 6, 8};
set<int> set2; // 构造空集合
set2.insert(ivec.cbegin(), ivec.cend()); // set2包含四个元素:2, 4, 6, 8
set2.insert({1, 3, 5, 7, 1, 3, 5, 7});   // set2包含8个元素: 1, 2, 3, 4, 5, 6, 7, 8

// map使用insert的四种方法
word_count.insert({word, 1});
word_count.insert(make_pair(word, 1));
word_count.insert(pair<string, size_t>(word, 1));
word_count.insert(map<string, size_t>::value_type(word, 1));

关联容器支持的insert操作如下:

insertemplace返回值依赖于容器类型和参数。对于不包含重复关键字的容器,添加单一元素的insertemplace版本返回一个pair,其first成员是一个迭代器指向具有给定关键字的元素,其second成员是一个bool值表示元素是插入成功还是已经存在于容器中。对于允许重复关键字的容器,接收单个元素的insert操作返回指向新元素的迭代器而不会返回bool值。

3. 删除元素

4. map的下标操作

mapunordered_map容器提供了下标运算符和一个对应的at函数。set类型因为没有与关键字相关联的“值”,因此不支持下标。对一个map使用下标时,如果该关键字不在容器中,那么会添加一个具有此关键字的元素到map中。

5. 访问元素

在关联容器中查找元素的操作包括:

在使用中我们需要注意:

string search_item("Alain de Botton");     // 要查找的作者
auto entries = authors.count(search_item); // 元素的数量
auto iter = authors.find(search_item);     // 此作者的第一本书
// 通过循环遍历该作者的书
while(entries) {
    cout << iter->second << endl;
    ++iter;
    --entries;
}
for (auto beg = authrors.lower_bound(search_item),
        end = authors.upper_bound(search_item);
        beg != end; ++beg)
    cout << beg->second << endl;
for (auto pos = authors.equal_range(search_item);
    pos.first != pos.second; ++pos.first)
    cout << pos.first->second << endl;

无序容器

新标准定义了4个无序关联容器,这些容器不是使用比较运算符来组织元素,而是使用一个哈希函数hash function和关键字类型的==运算符。

1. 管理桶

无须容器在存储上组织为一组桶,每个桶保存零个或者多个元素。无序容器使用一个哈希函数将元素映射到桶。为了访问一个元素,首先计算元素的哈希值然后决定搜索哪个桶。因此,无序容器的性能依赖于哈希函数的质量和桶的大小。

2. 无序容器管理操作

桶接口:

桶迭代:

哈希策略:

3. 无序容器对关键字类型的要求

默认情况下无序容器使用关键字类型的==运算符来比较元素,还使用一个hash<key_type>类型的对象来生成每个元素的哈希值。标准库为内置类型(包括指针)和一些标准库类型(string和智能指针)等类型定义了hash模板。因此我们可以直接定义关键字是内置类型(包括指针)、string和智能指针等类型的无序容器。

上一篇下一篇

猜你喜欢

热点阅读