C++ Primer 0x0B 学习笔记
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 0x0B 学习笔记相关的知识,希望对你有一定的参考价值。
📔 C++ Primer 0x0B 学习笔记
推荐阅读 《C++ Primer 5th》知识点总结&练习题解
-
关联容器支持高效的关键字查找和访问,
map
和set
是两个主要的关联容器 -
标准库提供8个关联容器
-
按关键字有序保存元素
map
:关联数组,保存关键字-值对set
:关键字即值,即值保存关键字的容器,底层实现是红黑树multimap
:关键字可重复出现的map
multiset
:关键字可重复出现的set
-
无序集合
-
unordered_map
:用哈希函数组织的map
-
unordered_set
:用哈希函数组织的set
-
unordered_multimap
:哈希组织的map
,关键字可重复出现 -
unordered_multiset
:哈希组织的set
,关键字可重复出现
-
-
11.1 使用关联容器
- 类似顺序容器,关联容器也是模板,使用的时候要明确关键字和值的类型
set
可以去重- 可以对关联容器的元素进行列表初始化
11.2 关联容器概述
- 关联容器不支持顺序容器的位置相关的操作如
push_front
或push_back
- 关联容器的迭代器都是双向的
11.2.1 定义关联容器
- 定义一个
map
,必须既指明关键字类型又指明值类型 - 定义一个
set
,只需指明关键字类型,因为set
中没有值 - 每个关联容器都定义了一个默认构造函数,创建一个指定类型的空容器
- 关联容器初始化:同类型容器的拷贝,一个值范围,初始化列表
11.2.2 关键字类型的要求
- 有序容器要求所提供的操作必须在关键字类型上定义一个严格弱序(可以自己定义)
list
迭代器不支持比较运算 - 为了使用自定义的操作,必须在定义关联容器类型时提供此操作的类型
11.2.3 pair 类型
pair
类型保存两个数据成员(first
和second
),类似容器。定义在头文件utility
中pair
的默认构造函数对数据进行值初始化- 函数要返回一个
pair
可以对返回值进行列表初始化return fisrt,second
,早期C++
不允许 - 可以使用
make_pair
来产生pair
对象
11.3 关联容器操作
关联容器定义了几个类型别名
key_type
此容器类型的关键字类型mapped_type
每个关键字关联的类型,只适用于map
value_type
对于set
和key_value
相同,对于map
为pair<const key_type,mapped_type>
11.3.1 关联容器迭代器
- 当解引用一个关联容器迭代器,我们会得到一个类型为容器的
value_type
的值的引用 - 对于
map
而言,value_type
是一个pair
类型,first
保存const
的关键字,second
保存值。我们可以改变pair
的值,但不能改变关键字成员的值 set
的迭代器是const
的,可以用一个set
迭代器来读取元素的值,但不能修改- 当使用一个迭代器遍历一个
map
、multimap
、set
或multiset
时,迭代器按关键字升序遍历元素 - 我们通常不对关联容器使用泛型算法,关键字是
const
这一特性意味着不能将关联容器传递给修改或重排容器元素的算法;关联容器可用于只读取元素的算法,但是这类算法很多都要搜索序列,关联容器不支持通过它们的关键字进行快速查找,所以也没什么用。 - 使用关联容器专用的
find
成员会比调用泛型算法的find
快得多 - 实际编程中,我们对一个关联容器使用算法要么是将它当作源序列,要么当作一个目的位置,可以使用泛型算法的
copy
将元素从一个关联容器拷贝到另一个序列
11.3.2 添加元素
- 由于
map
和set
(以及对应的无序类型)包含不重复的关键字,因此插入一个已存在的元素对容器没有任何影响 - 向一个
map
进行insert
操作时,必须记住元素是pair
insert
或emplace
的返回值依赖于容器类型和参数,对于不包含重复关键字的容器,添加单一元素的insert
和emplace
返回一个pair
告诉我们插入是否成功,first
成员是一个迭代器指向具有给定关键字的元素,second
成员是个bool
值,告诉我们插入成功还是已经在容器中了。如果是可重复类型的只返回一个迭代器
11.3.3 删除元素
关联容器提供三个版本的erase
c.erase(k)
,从c
中删除每个关键字为k
的元素,返回一个size_type
值,指出删除的元素数量,这个是顺序容器没有的c.erase()
,从c
中删除迭代器p
指定的元素,p
必须指向一个真实元素不能是c.end()
,返回一个指向p
之后元素的迭代器c.erase(b,e)
,删除迭代器对表示的范围中的元素,返回e
11.3.4 map的下标操作
set
,multimap
,unordered_multimap
类型不支持下标- 对一个
map
使用下标操作,其行为与数组或vecotr
上的下标操作很不相同,使用一个不在容器中的关键字作为下标,会添加一个具有此关键字的元素到map
中 c[k]
返回关键字为k
的元素,如果k
不在c
中则添加一个关键字为k
的元素,对其值进行值初始化c.at(k)
访问关键字为k
的元素,带参数检查,如果k
不再c
中,跑出一个out_of_range
异常- 对
map
进行下标操作会得到一个mapped_type
对象,解引用map
迭代器时,会得到一个value_type
对象,这与vector
、string
是不同的 map
的下标运算符返回的是一个左值,我们既可以读也可以写元素
11.3.5 访问元素
-
lower_bound
和upper_bound
不适用于无序容器 -
下标和
at
操作适用于非const
的map
和unordered_map
-
c.find(k)
返回一个迭代器,指向关键字为k
的元素,如果k
不在容器中,则返回尾后迭代器 -
c.count(k)
返回关键字等于k
的元素数量,对于不允许重复关键字的容器,返回值永远是0或1 -
c.lower_bound(k)
返回一个迭代器,指向第一个关键字不小于k
的元素,如果关键字不在容器中,则lower_bound
会返回关键字的第一个安全插入点(不影响容器中元素顺序的插入位置) -
c.upper_bound(k)
返回一个迭代器,指向第一个关键字大于k
的元素 -
c.equal_range(k)
返回一个迭代器pair
表示关键字等于k
的元素范围,若k
不存在,pair
的两成员均等于c.end()
(两个关键字都指向可以插入的位置) -
对
map
使用find
代替下标操作 -
如果
multimap
或multiset
中有多个元素具有给定关键字,则这些关键字会在容器中相邻存储find(k)
返回一个迭代器指向第一个关键字为k
的元素 -
可以通过
lower_bound
和upper_bound
,获得一对迭代器对形成的范围,表示具有该关键字的元素的范围,如果没有与给定关键字匹配的元素,lower_bound
和upper_bound
返回相同的迭代器
11.4 无序容器
- 无需关联容器不使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的
==
运算符 - 如果关键字类型固有就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器
- 无序容器的性能依赖于哈希函数的质量和桶的数量和大小
- 标准库为内置类型提供了
hash
模板,还为一些标准库类型如string
、智能指针类型定义了hash
,所以我们可以直接定义关键字是内置类型(包括指针)、string
、智能指针类型的无序容器 - 不能直接定义关键字类型为自定义类型的无序容器,必须提供我们自己的
hash
模板版本。为了使用自定义类型作为关键字,我们可以采用另一种方法:提供函数来替代==
运算符和哈希值计算函数
以上是关于C++ Primer 0x0B 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章