菜狗的C++ primer读书笔记:第十一章 关联容器

来源:互联网 发布:jmeter 安装mac版 编辑:程序博客网 时间:2024/05/21 23:01

1.     关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的。与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。

2.     关联容器支持高效的关键字查找和访问。两个主要的关联容器类型:map中的元素是一些关键字-值对,其中关键字起到索引的作用,值则表示与索引相关联的数据;set中每个元素只包含一个关键字,支持高效的关键字查询操作。

3.     关联容器类型:

分别定义在map、set、unordered_map、unordered_set头文件中。

4.     关联容器支持普通容器操作,但不支持顺序容器的位置相关的操作。原因是关联容器中元素是根据关键字存储的,这些操作对关联容器没有意义,而且关联容器也不支持构造函数或插入操作这些接受一个元素值和一个数量值的操作。

5.     关联容器的迭代器都是双向的。

6.     类似顺序容器,关联容器也是模板。定义一个set时,只需指明关键字类型;定义一个map时,必须既指明关键字类型又指明值类型。

7.     每个关联容器都定义了一个默认构造函数,它创建一个指定类型的空容器。我们也可以将关联容器初始化为另一个同类型容器的拷贝,或是从一个值的范围来初始化关联容器,只要这些值可以转化为容器所需类型即可。在新标准下,我们也可以对关联容器进行值初始化。初始化map时我们将每个关键字-值对包围在花括号中:{key , value} 。

8.     一个map或者set中的关键字必须是唯一的,对一个给定的关键字只能有一个元素的关键字等于它。容器multimap和multiset没有此限制,它们都允许多个元素具有相同的关键字。

9.     关联容器对其关键字类型有些限制。对于有序容器(map、multimap、set、multiset),关键字必须定义元素比较的方法。默认情况下,标准库使用关键字类型的<运算符来比较两个关键字。在集合类型中,关键字类型就是元素类型;在映射类型中,关键字类型是元素的第一部分的类型。

10.  可以向算法提供我们自己定义的比较操作,同样也可以提供自己定义的操作来代替关键字上的<运算符。但所提供的操作都必须符合严格弱序(可看做“小于等于”),必须具备如下基本性质:


       如果两关键字等价,那么容器将它们视作相等来处理。当用作map的关键字时,只能有一个元素与这两个关键字关联,我们可以用两者中任意一个来访问相应值。

11.  为了指定使用自定义的操作,必须在定义关联容器类型时提供此操作的类型,自定义的操作类型必须在尖括号中紧跟着元素类型给出。且在尖括号中出现的每个类型仅仅就是个类型而已,当我们创建一个容器(对象)时,才会以构造函数参数的形式提供真正的比较操作。

12.  比较操作类型应该是一种函数指针类型,我们使用decltype来获得一个函数指针类型时,必须加上一个*来指出我们要使用一个给定函数类型的指针。

13.  map的元素类型时pair,标准库类型pair定义在头文件utility中。一个pair保存两个数据成员,作为模板需要提供两个类型名。pair的构造函数对数据成员进行值初始化。pair的数据成员时public的,两个成员分别命名为first和second。

14.  pair的操作:

15.  关联容器额外的类型别名:

由于我们不能改变一个元素的关键字,因此这些pair的关键字部分是const的。使用作用域运算符来提取一个类型的成员。必须记住,一个map的value_type是一个pair,我们可以改变pair的值,但不能改变关键字成员的值。

16.  虽然set类型同时定义了iterator和const_iterator类型,但是两种类型都只允许只读访问set中的元素。与map中关键字一样,set中关键字也是const的。可以用set的迭代器来读取元素的值,但不能修改。

17.  当使用一个迭代器遍历一个有序关联容器时,迭代器按关键字升序遍历元素。

18.  通常不对关联容器使用泛型算法。一方面,关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法;另一方面,关联容器虽然可用于只读取元素的算法,但这类算法都要搜索序列,由于关联容器不能通过关键字进行快速查找,因此使用泛型算法并不明智。在实际编程中,如果我们对一个关联容器使用算法,一般是将它当作一个源序列或者当作一个目的位置。

19.  关联容器的insert操作:

对一个map进行insert操作时,元素类型必须是pair。

对multi前缀的关联容器,因为其允许重复关键字,所以接受单个元素的insert操作返回一个指向新元素的迭代器。

20.  关联容器的erase操作:

21.  关联容器map的下标操作:

map和unordered_map容器提供了下标运算符和一个对应的at函数,而set类型不支持下标操作

对于一个map使用下标操作,与数组或者vector的下标操作不同:使用一个不再容器中的关键字作为下标,会添加一个具有此关键字的元素到map中。因为它的下标运算符可能插入元素,所以只能对非const的map使用下标操作。

与vector等容器不同的另一点,map的下标运算符返回的类型(mapped_type)与解引用map迭代器得到的类型(value_type)不同。

22.  关联容器中查找元素的操作:

应该使用哪个操作依赖于我们要解决什么问题,以及我们使用的容器类型。

23.  因为map类型的下标操作会在容器中没有该关键字时会向其中插入一个具有给定关键字的元素,所以不能用下标运算符来检查一个元素是否存在,这种情况下应该使用find来查询map中元素的有无。

24.  如果在multimap和multiset中有多个元素具有给定关键字,则这些元素在容器中会相邻存储,在此类容器中查找元素有三种方法:

①   首先使用count确定元素个数,再利用find获得迭代器进行遍历。(当我们遍历一个multimap或multiset时,保证可以得到序列中所有具有给定关键字的元素)

②   用相同的关键字调用lower_bound和upper_bound会得到一个迭代器范围,表示所有具有该关键字的元素的范围,如果两个成员函数返回相同的迭代器则说明关键字不在容器中。(如果关键字不在容器中,lower_bound会返回关键字的第一个安全插入点,该插入点不会影响容器中元素顺序)

③   equal_range函数接受关键字,返回一个迭代器<pair>。若关键字存在,则第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置;若未找到匹配元素,则两个迭代器都指向关键字可以插入的位子。

25.  无序关联容器不是使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。无序关联容器的适用情况:关键字类型的元素没有明显的序关系时;维护元素的序代价非常高昂时(性能测试时发现问题可以用哈希技术解决)。

26.  通常可以用一个无序容器替换对应的有序容器,反之亦然,但是由于元素未按顺序储存,一个无序容器的输出通常会与有序容器版本不同。

27.  无序容器在存储上组织为一组桶,每个桶保存零个或多个元素。其使用哈希函数将元素映射到桶,并将具有一个特定哈希值的所有元素都保存在相同的桶中。无序容器的性能依赖于哈希函数的质量和桶的数量和大小。计算一个元素的哈希值和在桶中搜索通常是很快的操作,但当桶中元素太多时查找特定元素就需要量比较操作。

28.  无序容器提供了一组管理桶的函数,它们允许我们查询容器的状态以及在必要时强制容器进行重组。

无序容器的操作:

除了哈希管理操作之外,无序容器还提供了与有序容器相同的一些操作。

29.  默认情况下,无序容器使用关键字类型的==运算符来比较元素,并使用一个hash<key_type> 类型的对象来生成每个元素的哈希值。标准库为内置类型、string、智能指针类型等定义了hash,因此我们可以直接定义关键字是这些类型的无序容器。但是我们不能直接定义关键字类型为自定义类类型的无序容器,必须提供自己定义的hash模板版本,也可通过重载函数来替代==运算符和哈希值计算函数。

阅读全文
0 0
原创粉丝点击