doc/docs/Cpp-Notes-main/Cpp-Primer/11.关联容器.md
sairate b5160be045 docs(book): 添加现代 C++教程及相关代码
- 新增现代 C++ 教程的 Preface 章节,包括英文和中文版本
- 添加 C++ Primer 练习代码
- 新增 Learn C++ 教程的 C++ 开发简介章节
- 添加头文件解析文档
- 更新 mkdocs.yml,包含新教程的目录结构
- 修改项目设置,使用 Python 3.10环境
2025-07-06 16:14:30 +08:00

145 lines
7.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 第十一章 关联容器
- 关联容器和顺序容器的不同:关联容器中的元素时按照**关键字**来保存和访问的。
- 关联容器支持通过关键字来高效地查找和读取元素,基本的关联容器类型是 `map``set`
**关联容器类型**
| 容器类型 | 解释 |
|-----|-----|
| 按顺序存储 | |
| `map` | 关键数组:保存`关键字-值`对 |
| `set` | 关键字即值,即只保存关键字的容器 |
| `multimap` | 支持同一个键多次出现的`map` |
| `multiset` | 支持同一个键多次出现的`set` |
| 无序集合 | |
| `unordered_map` | 用哈希函数组织的`map` |
| `unordered_set` | 用哈希函数组织的`set` |
| `unordered_multimap` | 哈希组织的`map`,关键字可以重复出现 |
| `unordered_multiset` | 哈希组织的`set`,关键字可以重复出现 |
## 关联容器概述
### 定义关联容器
- 需要指定元素类型。
- 列表初始化:
- `map``map<string, int> word_count = {{"a", 1}, {"b", 2}};`
- `set``set<string> exclude = {"the", "a"};`
### 关键字类型的要求
- 对于有序容器,关键字类型必须定义元素比较的方法。默认是`<`
- 如果想传递一个比较的函数,可以这样定义:`multiset<Sales_data, decltype(compareIsbn)*> bookstore(compareIsbn);`
### pair
-`utility`头文件中定义。
- 一个`pair`保存两个数据成员,两个类型不要求一样。
**pair的操作**
| 操作 | 解释 |
|-----|-----|
| `pair<T1, T2> p;` | `p`是一个`pair`,两个类型分别是`T1``T2`的成员都进行了值初始化。 |
| `pair<T1, T2> p(v1, v2);` | `first``second`分别用`v1``v2`进行初始化。 |
| `pair<T1, T2>p = {v1, v2};` | 等价于`p(v1, v2) |
| `make_pair(v1, v2);` | `pair`的类型从`v1`和`v2`的类型推断出来。 |
| `p.first` | 返回`p`的名为`first`的数据成员。 |
| `p.second` | 返回`p`的名为`second`的数据成员。 |
| `p1 relop p2` | 运算关系符按字典序定义。 |
| `p1 == p2` | 必须两对元素两两相等 |
| `p1 != p2` | 同上 |
## 关联容器操作
**关联容器额外的类型别名**
| 类型别名 | 解释 |
|-----|-----|
| `key_type` | 此容器类型的关键字类型 |
| `mapped_type` | 每个关键字关联的类型,只适用于`map` |
| `value_type` | 对于`map`,是`pair<const key_type, mapped_type>`; 对于`set`,和`key_type`相同。 |
### 关联容器迭代器
- 解引用一个关联容器迭代器时,会得到一个类型为容器的`value_type`的值的引用。
- `set`的迭代器是`const`的。
- 遍历关联容器:使用`begin`和`end`,遍历`map`、`multimap`、`set`、`multiset`时,迭代器按**关键字升序**遍历元素。
### 添加元素
**关联容器`insert`操作**
| `insert`操作 | 关联容器 |
|-----|-----|
| `c.insert(v)` `c.emplace(args)` | `v`是`value_type`类型的对象;`args`用来构造一个元素。 对于`map`和`set`,只有元素的关键字不存在`c`中才插入或构造元素。函数返回一个`pair`,包含一个迭代器,指向具有指定关键字的元素,以及一个指示插入是否成功的`bool`值。对于`multimap`和`multiset`则会插入范围中的每个元素。|
| `c.insert(b, e)` `c.insert(il)` | `b`和`e`是迭代器,表示一个`c::value_type`类型值的范围;`il`是这种值的花括号列表。函数返回`void`。对于 `map`和`set`,只插入关键字不在`c`中的元素。 |
| `c.insert(p, v)` `c.emplace(p, args)` | 类似`insert(v)`,但将迭代器`p`作为一个提示,指出从哪里开始搜索新元素应该存储的位置。返回一个迭代器,指向具有给定关键字的元素。 |
向`map`添加元素:
- `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));`
### 删除元素
**从关联容器中删除元素**
| 操作 | 解释 |
|-----|-----|
| `c.erase(k)` | 从`c`中删除每个关键字为`k`的元素。返回一个`size_type`值,指出删除的元素的数量。 |
| `c.erase(p)` | 从`c`中删除迭代器`p`指定的元素。`p`必须指向`c`中一个真实元素,不能等于`c.end()`。返回一个指向`p`之后元素的迭代器,若`p`指向`c`中的尾元素,则返回`c.end()` |
| `c.erase(b, e)` | 删除迭代器对`b`和`e`所表示范围中的元素。返回`e`。 |
### 下标操作
**`map`和`unordered_map`的下标操作**
| 操作 | 解释 |
|-----|-----|
| `c[k]` | 返回关键字为`k`的元素;如果`k`不在`c`中,添加一个关键字为`k`的元素,对其值初始化。 |
| `c.at(k)` | 访问关键字为`k`的元素,带参数检查;若`k`不存在在`c`中,抛出一个`out_of_range`异常。 |
### 查找元素
**在一个关联容器中查找元素**:
| 操作 | 解释 |
|-----|-----|
| `c.find(k)` | 返回一个迭代器,指向第一个关键字为`k`的元素,若`k`不在容器中,则返回尾后迭代器 |
| `c.count(k)` | 返回关键字等于`k`的元素的数量。对于不允许重复关键字的容器返回值永远是0或1。 |
| `c.lower_bound(k)` | 返回一个迭代器,指向第一个关键字**不小于**`k`的元素。 |
| `c.upper_bound(k)` | 返回一个迭代器,指向第一个关键字**大于**`k`的元素。 |
| `c.equal_range(k)` | 返回一个迭代器`pair`,表示关键字等于`k`的元素的范围。若`k`不存在,`pair`的两个成员均等于`c.end()`。 |
- `lower_bound`和`upper_bound`不适用于无序容器。
- 下标和`at`操作只适用于非`const`的`map`和`unordered_map`。
## 无序容器
- 有序容器使用比较运算符来组织元素;无序容器使用哈希函数和关键字类型的`==`运算符。
- 理论上哈希技术可以获得更好的性能。
- 无序容器在存储上组织为一组桶(bucket),每个桶保存零个或多个元素。无序容器使用一个哈希函数将元素映射到桶。
**无序容器管理操作**
| 操作 | 解释 |
|-----|-----|
| **桶接口** | |
| `c.bucket_count()` | 正在使用的桶的数目 |
| `c.max_bucket_count()` | 容器能容纳的最多的桶的数目 |
| `c.bucket_size(n)` | 第`n`个桶中有多少个元素 |
| `c.bucket(k)` | 关键字为`k`的元素在哪个桶中 |
| **桶迭代** | |
| `local_iterator` | 可以用来访问桶中元素的迭代器类型 |
| `const_local_iterator` | 桶迭代器的`const`版本 |
| `c.begin(n)``c.end(n)` | 桶`n`的首元素迭代器 |
| `c.cbegin(n)``c.cend(n)` | 与前两个函数类似,但返回`const_local_iterator`。 |
| **哈希策略** | |
| `c.load_factor()` | 每个桶的平均元素数量,返回`float`值。 |
| `c.max_load_factor()` | `c`试图维护的平均比桶大小,返回`float`值。`c`会在需要时添加新的桶,以使得`load_factor<=max_load_factor` |
| `c.rehash(n)` | 重组存储,使得`bucket_count>=n`,且`bucket_count>size/max_load_factor` |
| `c.reverse(n)` | 重组存储,使得`c`可以保存`n`个元素且不必`rehash`。 |