1. 使用关联容器
关联容器通过关键字保存和访问元素。顺序容器按照在容器的位置保存和访问元素。
关联容器可以按照不同的特性分类,底层是map
或者set
。根据能否有重复的关键字可以加上muti
,根据是否按顺序保存可以加上unordered_
。
Map和Set的底层都是红黑树。
set它可以在 O(n log n) 的时间排序数组,O(log n) 的时间插入、删除、查找任意值,O(log n) 的时间获得最小或最大值。
关联容器也是模板,在创建对象时,需要指明元素类型。
1.1 定义关联容器
每个关联容器都定义了一个默认构造函数,它创建一个指定类型的空容器。
除此以外,还能用另一个同类型的关联容器的拷贝来初始化。或者用值范围来初始化。
map类型中,第一个元素为关键字,第二个元素为值。
muti版本的关联容器和普通版本定义方式一样,不过允许重复关键字。
1.2 关键字类型的要求
有序关联容器的元素必须定义元素之间比较的方法。且该比较必须是严格弱序的:
可以将自定义的比较操作以函数指针的方式传递给有序关联元素。
也可以直接用compareIsbn和&compareIsbn作为参数,因为当使用函数名字时,在需要的时候会自动转为指针。
1.3 pair类型
pair
是一种标准库类,定义在utility
头文件下。pair也是模板,创建pair时,需要提供两个类型名。
pair的默认构造函数对数据成员进行值初始化。
pair的数据成员first
和second
是public
的,可以直接用成员访问符访问。
可对返回值进行列表初始化:
显式构造返回值:
隐式构造返回值:
调用makepair函数:
2. 关联容器操作
示例如下:
2.1 关联容器迭代器
用法和顺序容器迭代器没啥区别,只是解引用一个关联容器迭代器会得到一个value_type类型的值的引用。
map的存储的元素的pair,它的first存储的const
的关键字,second保存成员值。
尽管set同时定义了iterator和const_iterator类型,但是这两种类型都只能读set中的元素。set的关键字都是const的,不允许修改set的关键字。
用常规迭代器遍历方法遍历有序关联容器得到的结果是排好序的:
一般不对关联容器使用泛型算法。
1.无法使用修改或者重排元素的算法。关联容器的关键字是const
,使得这一行为不可能。
2.对关联容器使用只读算法的效率不高。这类算法大多要搜索序列,关联容器不能通过关键字快速查找。使用关联容器自带的find效率要高的多。
一般来说,可以用拷贝算法把一个关联容器拷贝到另一个序列。也可使用插入迭代器绑定某个关联容器,通过该迭代器使用算法。除此以外,泛型算法一般不用于关联容器。
2.2 添加元素
对于multi版本的关联容器,无需返回bool值,因为插入一定成功。
对于一个给定的关键字,只有第一个带这个关键字的元素才被插入到容器中。
2.3 删除元素
关联容器提供了根据关键字删除的额外函数。
2.4 map下标操作
不能对set使用下标操作,因为set元素本身就是关键字,没有与之相关联的值。
不能对multi版本的map使用下标操作,因为同一关键字对应的值可能不唯一。
通过关键字访问对应的值时,如果map中没有相应的关键字,会为它创建一个元素插入到map内,与它关联的值进行值初始化。如果不想自动添加,可使用at
。
不能对const的map使用下标操作。
2.5 访问元素
使用find
代替下表运算符来访问元素。不会导致自动创建新的 关键字-值 对。
在multi版本的map和set而言,同一关键字对应的元素在容器中相邻存储。
给定从作者到著作的映射(允许一个作者有多个著作),如何打印该作者的所有著作:
使用multi
和有序版本的map
,允许键值重复,元素按照键值排序:
1.先用count计算该作者的著作总数,再用find找到第一本著作,然后依次输出指定数目的著作名。
2.可直接使用lower_bound和upper_bound获取该作者的第一本著作和最后一本著作的后面位置(左闭右开)。然后输出中间部分即可。
3.或者直接使用equal_range。返回的范围也是左闭右开区间。
3. 无序容器
无序容器相对而言性能更好。容器不是采用元素之间的大小关系而是使用哈希函数和等于运算符组织元素。
无序容器用一组桶存储元素,元素的哈希值反映了所在哪个桶,在桶内顺序搜索得到想要的元素。哈希函数的质量和桶的数目和大小决定了无序容器的效率。
使用关键字的==运算符比较元素,使用hash<key_type>类型的对象计算每个元素的哈希值。这对关键字的类型有一定要求。
可以直接定义关键字是内置类型、string、智能指针类型的无序容器。因为标准库为这三种类型提供了hash模板。
但是不能直接定义自定义类型的无序容器,需要提供函数代替 ==
运算符和哈希值计算函数。