C++ Primer 0x0B 学习笔记

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 0x0B 学习笔记相关的知识,希望对你有一定的参考价值。

📔 C++ Primer 0x0B 学习笔记

更好的阅读体验(实时更新与修正)

推荐阅读 《C++ Primer 5th》知识点总结&练习题解

  • 关联容器支持高效的关键字查找和访问,mapset是两个主要的关联容器

  • 标准库提供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_frontpush_back
  • 关联容器的迭代器都是双向的

11.2.1 定义关联容器

  • 定义一个map,必须既指明关键字类型又指明值类型
  • 定义一个set,只需指明关键字类型,因为set中没有值
  • 每个关联容器都定义了一个默认构造函数,创建一个指定类型的空容器
  • 关联容器初始化:同类型容器的拷贝,一个值范围,初始化列表

11.2.2 关键字类型的要求

  • 有序容器要求所提供的操作必须在关键字类型上定义一个严格弱序(可以自己定义)list迭代器不支持比较运算
  • 为了使用自定义的操作,必须在定义关联容器类型时提供此操作的类型

11.2.3 pair 类型

  • pair类型保存两个数据成员(firstsecond),类似容器。定义在头文件utility
  • pair的默认构造函数对数据进行值初始化
  • 函数要返回一个pair可以对返回值进行列表初始化return fisrt,second,早期C++不允许
  • 可以使用make_pair来产生pair对象

11.3 关联容器操作

关联容器定义了几个类型别名

  • key_type此容器类型的关键字类型
  • mapped_type每个关键字关联的类型,只适用于map
  • value_type对于setkey_value相同,对于mappair<const key_type,mapped_type>

11.3.1 关联容器迭代器

  • 当解引用一个关联容器迭代器,我们会得到一个类型为容器的value_type 的值的引用
  • 对于map而言,value_type是一个pair类型,first保存const的关键字,second保存值。我们可以改变pair的值,但不能改变关键字成员的值
  • set的迭代器是const的,可以用一个set迭代器来读取元素的值,但不能修改
  • 当使用一个迭代器遍历一个mapmultimapsetmultiset时,迭代器按关键字升序遍历元素
  • 我们通常不对关联容器使用泛型算法,关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法;关联容器可用于只读取元素的算法,但是这类算法很多都要搜索序列,关联容器不支持通过它们的关键字进行快速查找,所以也没什么用。
  • 使用关联容器专用的find成员会比调用泛型算法的find快得多
  • 实际编程中,我们对一个关联容器使用算法要么是将它当作源序列,要么当作一个目的位置,可以使用泛型算法的copy将元素从一个关联容器拷贝到另一个序列

11.3.2 添加元素

  • 由于mapset(以及对应的无序类型)包含不重复的关键字,因此插入一个已存在的元素对容器没有任何影响
  • 向一个map进行insert操作时,必须记住元素是pair
  • insertemplace的返回值依赖于容器类型和参数,对于不包含重复关键字的容器,添加单一元素的insertemplace返回一个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的下标操作

  • setmultimapunordered_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对象,这与vectorstring是不同的
  • map的下标运算符返回的是一个左值,我们既可以读也可以写元素

11.3.5 访问元素

  • lower_boundupper_bound不适用于无序容器

  • 下标和at操作适用于非constmapunordered_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代替下标操作

  • 如果multimapmultiset中有多个元素具有给定关键字,则这些关键字会在容器中相邻存储find(k)返回一个迭代器指向第一个关键字为k的元素

  • 可以通过lower_boundupper_bound,获得一对迭代器对形成的范围,表示具有该关键字的元素的范围,如果没有与给定关键字匹配的元素,lower_boundupper_bound返回相同的迭代器

11.4 无序容器

  • 无需关联容器不使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符
  • 如果关键字类型固有就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器
  • 无序容器的性能依赖于哈希函数的质量和桶的数量和大小
  • 标准库为内置类型提供了hash模板,还为一些标准库类型如string、智能指针类型定义了hash,所以我们可以直接定义关键字是内置类型(包括指针)、string、智能指针类型的无序容器
  • 不能直接定义关键字类型为自定义类型的无序容器,必须提供我们自己的hash模板版本。为了使用自定义类型作为关键字,我们可以采用另一种方法:提供函数来替代==运算符和哈希值计算函数

以上是关于C++ Primer 0x0B 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 0x09 学习笔记

C++ Primer笔记11---chapter11 关联容器

C++ Primer 0x10 学习笔记

C++ Primer 0x0E 学习笔记

C++ Primer 0x0E 学习笔记

C++ Primer笔记9---chapter9 顺序容器