《c++ primer》 第11章 关联容器 学习笔记

来源:互联网 发布:ubuntu镜像文件 编辑:程序博客网 时间:2024/06/05 04:44

11.1使用关联容器

按关键字有序保存元素  
 
map                       关联数组:保存关键字-值对应            头文件map   set                      关键字既值,既只保存关键字的容器        头文件set   multimap                 关键字可重复出现的map                 头文件map   multiset                 关键字可重复出现的set                 头文件set  无序集合   unordered_map            用hash函数组织的map                  头文件unordered_map   unordered_set            用hash函数组织的set                  头文件unordered_set   unordered_multimap       hash组织的map:关键字可重复出现        头文件unordered_map   unordered_multiset       hash组织的set:关键字可重复出现        头文件unordered_set  

map是关键字-值对的集合。map类型通常被称为关联数组。
set是关键字的简单集合。


使用map

初始化:值初始化、列表初始化
map是关键字-值对的集合。

11.2关联容器概述

关联容器不支持顺序容器的位置相关操作,如push_back等。关联容器的迭代器都是双向的。

11.2.1定义关联容器

map是关键字-值对的有序集合。它会自动从小到大排序,且关键字只能出现一次。
set是只有关键字有序集合。
关联容器进行值初始化。
multimap和multiset关键字可以相同。

可以看见,对于map和set,我们输入时候是乱序的并且有重复的关键字,输出时有序不重复的

课后题11.7

11.2.2关键字类型的要求

有序容器关键字类型必须定义元素的比较方法。默认情况下是用<运算符来比较两个关键字。

有序容器的关键字类型

当然不想使用默认的<运算符排序时,我们可以采用我们自定义的操作,如排序函数等等。和泛型算法中的sort()接受一个谓词一样的道理。但是我们所提供的操作(排序函数)在关键字类型上定义了一个严格弱序(小于等于)。

使用关键字类型的比较函数

用来组织一个容器中元素的操作的类型也是该容器类型的一部分。为了指定使用自定义的操作,必须在定义关联容器类型时提供此操作的类型。用尖括号指出要定义哪种类型的容器,自定义的操作类型(函数指针类型)必须在尖括号中紧跟着元素类型给出。set<int,decltype(function)*>.比如一个类就不能当关键字,因为默认操作中是<运算符。但是我们可以自定义比较函数,使用类中的数据成员来定义一个严格弱序。为了使它能够按照我们的要求(比如大于顺序)排列,就要定义一个比较函数。在定义multiset时我们必须定义两个类型:一是关键字类型,二是比较操作类型-函数指针类型,指向比较函数。当定义此容器类型的对象时,需要提供想要使用的操作的指针。
即 multiset<class1,decltype(function)*> aset (function) 

课后题11.9

11.2.3 pair类型

定义在标准库#include <utility>里,pair是map容器的单独元素类型。

pair的默认构造函数对数据成员进行值初始化。一个pair保存两个数据成员(是public的),一个是first,一个是second.

pair初始化:值初始化,列表初始化(赋值初始化和直接初始化),make_pair()

创建pair对象的函数

有些函数需要返回一个pair,我们可以对返回值进行列表初始化(c++11指出return一个列表)

pair<int,int> function(int a,int b){return {a,b};//c++11return make_pair( );//c++11,构造空的pairreturn pair<int,int>(a,b);//之前版本的返回形式:显式初始化return make_pair(a,b);//}

11.3关联容器操作

key_type             此容器的关键字类型mapped_type          每个关键字关联的类型,只适用于mapvalue_type           对于set,和key_type相同(变量类型 )          对于map,为pair<const key_type, mapped_type>

11.3.1关联容器迭代器

map:value_type是一个pair类型,其first成员保存const的关键字,second成员保存值
set:set的迭代器是const的,只允许访问set中的关键字。
map和set支持begin()和end()操作。

11.3.2添加元素

c.insert()有两个版本,分别接受一对迭代器和一对参数列表,返回一对pair,first成员是一个迭代器,指向具有给定关键字的元素,second成员是一个bool值,指出元素是成功还是失败(之间已经有这个元素了)。insert对set,map添加元素,添加重复的元素对这两个容器没有其他影响。

向map中添加元素:

c.insert((1,1));c.insert(make_pair(1,1));c.insert(pair<int,int>(1,1));c.insert(map<int,int>::value_type(1,1));c.insert(b,e);

向set中添加元素:

c.insert(il);c.insert(b,e);

向multimap或multiset中添加元素:

可以插入具有相同关键字的元素。

接受单个元素的insert操作返回一个指向新元素的迭代器。这里不需要返回一个bool值,因为insert总是向这个容器中加入一个新元素。


11.3.3删除元素

与顺序容器删除操作很相似。

c.erase(p); 返回一个迭代器,指向p之后元素的迭代器c.erase(b,e);返回ec.erase(k);k为关键字,返回删除元素的数量

11.3.4map的下标操作

map支持下标运算符和c.at()函数,下标运算符中接受一个关键字。如果关键字不在map中,会自动创建一个元素插入到map中,关联值被初始化
set不支持下标运算符
c.[k]     k不在c中,就插入一个
c.at[k]   k不在c中,抛出异常
下标操作返回类型是maped_type对象,是个左值。

11.3.5访问元素

c.find(k)          返回一个迭代器,指向第一个关键字的元素 c.count(k)         返回一个数字,表明有多少元素有这个关键字c.lower_bound(k)   返回一个迭代器,指向第一个关键字不小于k的元素  >=c.upper_bound(k)   返回一个迭代器,指向第一个关键字大于k的元素    >c.equal_range(k)   返回一个关键字pair,表示关键字等于k的元素范围

对于不允许重复关键字的容器,两个函数都一样
对于允许重复关键字的容器,两个函数不一样

11.4无序容器

unordered_map          用hash函数组织的map                     头文件unordered_map  unordered_set          用hash函数组织的set                     头文件unordered_set  unordered_multimap     hash组织的map:关键字可重复出现           头文件unordered_map  unordered_multiset     hash组织的set:关键字可重复出现           头文件unordered_set  

这些容器不是使用比较运算符来组织元素的,而是使用一个哈希函数和关键字类型的==运算符。

无序容器提供了和有序容器相同的操作(初始化,赋值,添加insert,删除erase,下标操作,访问find、count)。也有允许关键字重复的版本。

但是无序容器的输出和有序容器的输出不同,因为是无序的。无序容器在存储上组织为一组桶,每个桶保存零个或者多个元素。无序容器使用一个哈希函数将元素映射到桶。为了访问一个元素,容器首先计算元素的哈希值,它指出应该搜索哪个桶。如果容器允许重复关键字,所有具有相同关键字的元素也都会在同一个桶中。因此无序容器的质量依赖于hash函数的质量和桶的大小和数量。

分别是g++和vs调试的结果,可以发现结果并不相同。


无序容器对关键字类型的要求

默认情况下,无序容器使用关键字==来比较元素,它们还使用了一个hash<key_type>类型的对象来生成每个元素的hash值。

但是我们不能定义关键字类型为自定义类类型的无序容器。与容器不同,不能直接使用hash模板,而是必须提供我们自己的hash模板

但是有另外一种方法:为了将自己的类当作关键字,我们要自己提供==运算符和hash值计算函数。

然后定义。

如:

using SD_multiset = unordered_multiset<Sales_datam decltype(hasher)*, decltype(eqop)*>;  //hasher是自己定义的hash函数,eqop是自己定义的==运算符。  SD_multiset bookstroe(43, hasher, eqop);//初始化  


1 0