C++primer第十一章 关联容器 11.1使用关联容器 11.2 关联容器概述

  • 关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的。与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的
  • 虽然关联容器的很多行为与顺序容器相同,但其不同之处反映了关键字的作用
  • 关联容器支持高效的关键字查找和访问。两个主要的关联容器(associative-container)类型是map和set。map中的元素是一些关键字-值(key-value)对关键字起到索引的作用,值则表示与索引相关联的数据。set中每个元素只包含一个关键字;set支持高效的关键字查询操作--检查一个给定关键字是否在set中。例如,在某些文本处理过程中,可以用一个set来保存想要忽略的单词。字典则是一个很好的使用map的例子:可以将单词作为关键字,将单词释义作为值。
  • 标准库提供8个关联容器,如表11.1所示。这8个容器间的不同体现在三个维度上:每个容器
  • (1)或者是一个set,或者是一个map;
  • (2)或者要求不重复的关键字,或者允许重复关键字;
  • (3)按顺序保存元素,或无序保存。允许重复关键字的容器的名字中都包含单词multi;不保持关键字按顺序存储的容器的名字都以单词unordered开头。因此一个unordered_multi_set是一个允许重复关键字,元素无序保存的集合,而一个set则是一个要求无重复关键字,有序存储的集合。无序容器使用哈希函数来组织元素,我们将在11.4节(第394页)中详细介绍有关哈希函数的更多内容。
  • 类型map和multimap定义在头文件map中;set和multiset定义在头文件set中;无序容器则定义在头文件unordered_map和unordered_set中。

11.1使用关联容器

  • 虽然大多数程序员都熟悉诸如vector和list这样的数据结构,但他们中很多人从未使用过关联数据结构。在学习标准库关联容器类型的详细内容之前,我们首先来看一个如何使用这类容器的例子,这对后续学习很有帮助。
  • map是关键字-值对的集合。例如,可以将一个人的名字作为关键字,将其电话号码作为值。我们称这样的数据结构为"将名字映射到电话号码”。map类型通常被称为关联数组。关联数组与''正常”数组类似,不同之处在于其下标不必是整数。我们通过一个关键字而不是位置来查找值。给定一个名字到电话号码的map,我们可以使用一个人的名字作为下标来获取此人的电话号码。
  • 与之相对,set就是关键字的简单集合。当只是想知道一个值是否存在时,set是最有用的。例如,一个企业可以定义一个名为bad_checks的set来保存那些曾经开过空头支票的人的名字。在接受一张支票之前,可以查询bad_checks来检查顾客的名字是否在其中。

 

  • 此程序读取输入,报告每个单词出现多少次。
  • 类似顺序容器,关联容器也是模板(参见3.3节,第86页)。为了定义一个map,我们必须指定关键字和值的类型。在此程序中,map保存的每个元素中,关键字是string类型,值是size_t类型(参见3.5.2节,第103页)。当对word_count进行下标操作时,我们使用一个string作为下标,获得与此string相关联的size_t类型的计数器。while循环每次从标准输入读取一个单词。它使用每个单词对word_count进行下标操作。如果word还未在map中,下标运算符会创建一个新元素,其关键字为word,值为0。不管元素是否是新创建的,我们将其值加1
  • 一旦读取完所有输入,范围for语句(参见3.2.3节,第81页)就会遍历map,打印每个单词和对应的计数器。当从map中提取一个元素时,会得到一个pair类型的对象,我们将在11.2.3节(第379页)介绍它。简单来说,pair是一个模板类型,保存两个名为first和second的(公有)数据成员。map所使用的pair用first成员保存关键字,用second成员保存对应的值。因此,输出语句的效果是打印每个单词及其关联的计数器。

使用 set

  • 上一个示例程序的一个合理扩展是:忽略常见单词,如"the", "and", "or"等。我们可 以使用set保存想忽略的单词,只对不在集合中的单词统计出现次数:

  • 与其他容器类似,set也是模板。为了定义一个set,必须指定其元素类型,本例中是string。与顺序容器类似,可以对一个关联容器的元素进行列表初始化(参见9.2.4节,第300页)。集合exclude中保存了12个我们想忽略的单词。此程序与前一个程序的重要不同是,在统计每个单词出现次数之前,我们检查单词是否在忽略集合中,这是在if语句中完成的:
  • find调用返回一个迭代器。如果给定关键字在set中,迭代器指向该关键字。否则,find 返回尾后迭代器。在此程序中,仅当word不在exclude中时我们才更新word的计数器。

1 1 .2 关联容器概述

  • 关联容器(有序的和无序的)都支持9.2节 (第 294页)中介绍的普通容器操作(列于表9.2,第 295页)。关联容器不支持顺序容器的位置相关的操作,例如push_front 或 push_back。原因是关联容器中元素是根据关键字存储的,这些操作对关联容器没有意义。而且,关联容器也不支持构造函数或插入操作这些接受一个元素值和一个数量值的操作
  • 除了与顺序容器相同的操作之外,关联容器还支持一些顺序容器不支持的操作(参见表 11.7,第 388页)和类型别名(参见表11.3,第 381页)。此外,无序容器还提供一些
  • 用来调整哈希性能的操作,我们将在11.4节 (第 394页)中介绍。关联容器的迭代器都是双向的(参见10.5.1节,第 365页)。

11.2.1定义关联容器

  • 如前所示,当定义一个map时,必须既指明关键字类型又指明值类型;而定义一个set时,只需指明关键字类型,因为set中没有值。每个关联容器都定义了一个默认构造函数,它创建一个指定类型的空容器。我们也可以将关联容器初始化为另一个同类型容器的拷贝,或是从一个值范围来初始化关联容器,只要这些值可以转化为容器所需类型就可以。在新标准下,我们也可以对关联容器进行值初始化

  • 与以往一样,初始化器必须能转换为容器中元素的类型。对于set,元素类型就是关键字类型。
  • 当初始化一个map时,必须提供关键字类型和值类型。我们将每个关键字-值对包围在花括号中:{key,value}来指出它们一起构成了map中的一个元素。在每个花括号中,关键字是第一个元素,值是第二个。因此,authors将姓映射到名,初始化后它包含三个元素。

初始化multimap或multiset

  • 一个map或set中的关键字必须是唯一的,即,对于一个给定的关键字,只能有一个元素的关键字等于它。容器multimap和multiset没有此限制,它们都允许多个元素具有相同的关键字。例如,在我们用来统计单词数量的map中,每个单词只能有一个元素。另一方面,在一个词典中,一个特定单词则可具有多个与之关联的词义。
  • 下面的例子展示了具有唯一关键字的容器与允许重复关键字的容器之间的区别。首先,我们将创建一个名为ivec的保存int的vector,它包含20个元素:0到9每个整数有两个拷贝。我们将使用此vector初始化一个set和一个multiset:

  • 即使我们用整个ivec容器来初始化iset,它也只含有10个元素:对应ivec中每个不同的元素。另一方面,miset有 20个元素,与 ivec中的元素数量一样多。

11.2.2关键字类型的要求

  • 关联容器对其关键字类型有一些限制。对于无序容器中关键字的要求,我们将在11.4节 (第 396页)中介绍。对于有序容器map、multimap,  set以及multiset,关键字类型必须定义元素比较的方法。默认情况下,标准库使用关键字类型的 < 运算符来比较两个关键字。在集合类型中,关键字类型就是元素类型;在映射类型中,关键字类型是元素的第一部分的类型。因此,11.2节 (第 377页)中 word_count的关键字类型是 string.类似的,exclude的关键字类型也是string。
  • 传递给排序算法的可调用对象(参见10.3.1节,第344页)必须满足与关联容器中关键字一样的类型要求。

有序容器的关键字类型

  • 可以向一个算法提供我们自己定义的比较操作(参见10.3节,第344页),与之类似,也可以提供自己定义的操作来代替关键字上的<运算符。所提供的操作必须在关键字类型
    上定义一个严格弱序(strictweakordering)。可以将严格弱序看作"小于等于”,虽然实际定义的操作可能是一个复杂的函数。无论我们怎样定义比较函数,它必须具备如下基本性质:
  • 两个关键字不能同时“小于等于”对方;如果kl"小于等于”k2,那么k2绝不能“小于等于”kl。
  • 如果kl“小于等于”k2,且k2“小于等于”k3,那么kl必须“小于等于”k3。
  • 如果存在两个关键字,任何一个都不"小于等于"另一个,那么我们称这两个关键字是"等价”的。如果kl“等价于”k2,且k2“等价于”k3,那么kl必须“等价于”k3
  • 如果两个关键字是等价的(即,任何一个都不“小于等于”另一个),那么容器将它们视作相等来处理。当用作map的关键字时,只能有一个元素与这两个关键字关联,我们可以用两者中任意一个来访问对应的值。

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

  • 用来组织一个容器中元素的操作的类型也是该容器类型的一部分。为了指定使用自定义的操作,必须在定义关联容器类型时提供此操作的类型。如前所述,用尖括号指出要定义哪种类型的容器,自定义的操作类型必须在尖括号中紧跟着元素类型给出。
  • 在尖括号中出现的每个类型,就仅仅是一个类型而已。当我们创建一个容器(对象)时,才会以构造函数参数的形式提供真正的比较操作(其类型必须与在尖括号中指定的类型相吻合)

  • 此处,我们使用decltype来指出自定义操作的类型。记住,当用decltype来获得一个函数指针类型时,必须加上一个*来指出我们要使用一个给定函数类型的指针(参见6.7节,第223页)。用comparelsbn来初始化bookstore对象,这表示当我们向bookstore添加元素时,通过调用comparelsbn来为这些元素排序。即bookstore中的元素将按它们的ISBN成员的值排序。可以用comparelsbn代替&comparelsbn作为构造函数的参数,因为当我们使用一个函数的名字时,在需要的情况下它会自动转化为一个指针(参见6.7节,第221页)。当然,使用&comparelsbn的效果也是一样的。

11.2.3pair类型

  • 在介绍关联容器操作之前,我们需要了解名为pair的标准库类型,它定义在头文件utility中。
  • 一个pair保存两个数据成员。类似容器,pair是一个用来生成特定类型的模板。当创建一个pair时,我们必须提供两个类型名,pair的数据成员将具有对应的类型。两个类型不要求一样:

  • pair的默认构造函数对数据成员进行值初始化(参见3.3.1节,第 88页)。因此,anon是一个包含两个空string的 pair, line保存一个空string和一个空vector。 word_count中的size_t成员值为0,而 string成员被初始化为空。我们也可以为每个成员提供初始化器:
  • pair<string, string> author( "James", ”Joyce”};
  • 这条语句创建一个名为author的pair,两个成员被初始化为"James"和"Joyce”。与其他标准库类型不同,pair的数据成员是public的(参见7.2节,第240页)。两个成员分别命名为first和second。我们用普通的成员访问符号(参见1.5.2节,第20页)来访问它们,例如,在第375页的单词计数程序的输出语句中我们就是这么做的:
  • cout<<w.first << " occurs" << w.second<<((w.second>1)?"times":"time")<<endl;
  • 此处,w是指向map中某个元素的引用。map的元素是pair.在这条语句中,我们首先打印关键字元素的first成员,接着打印计数器second成员。标准库只定义了有限的几个pair操作,表11.2列出了这些操作。

创建pair对象的函数

  • 用想象有一个函数需要返回一个pair。在新标准下,我们可以对返回值进行列表初始化(参见6.3.2节,第203页)
pair<string, int>
process(vector<string> &v)
(
/ / 处理v
if (!v.empty())
return {v.back () , v.back () .size () }; // 列表初始化
else
return pair<stringz int> () ; // 隐式构造返回值
}
  • 若v 不为空,我们返回一个由v 中最后一个string及其大小组成的pair。否则,隐式构造一个空pair,并返回它。 在较早的C++版本中,不允许用花括号包围的初始化器来返回pair这种类型的对象, 必须显式构造返回值:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446693.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codeforces 791A-C语言解题报告

791A题目网址 题目解析 1.输入a,b,每一年a3;b2,问多少年a>b? 2.因为不知道需要循环多少次,使用while循环 代码 #include<stdio.h> #include<stdlib.h> #include<string.h> int main() {int a,b,i0;scanf("%d %d",&a,&b);while(a&l…

Redis Mac下安装与使用

目录一、下载安装包二、编译三、服务端与客户端命令1、服务端启动命令2、客户端连接命令3、服务端关闭命令一、下载安装包 官网地址&#xff1a;http://redis.io/download 下载后&#xff0c;解压放到任意目录下。 二、编译 打开终端&#xff0c;切换到 Redis 根目录&#x…

C++primer第十一章 关联容器 11.3关联容器操作 11.4 无序容器

11.3关联容器操作 除了表9.2(第295页)中列出的类型&#xff0c;关联容器还定义了表11.3中列出的类型。这些类型表示容器关键字和值的类型。对于set类型&#xff0c;key_type和value type是一样的&#xff1b;set中保存的值就是关键字。在一个map中&#xff0c;元素是关键字_值…

codeforces 977A-C语言解题报告

977A题目网址 题目解析 1,输入数字n,运算次数k,当n最后一个数字是0时,n/10;当n最后一个数字不是0时,n-1;输出n 举例: 输入: 512 4 输出: 50 2.注意:当n最后一个数字是0时,使用n%100去判断 代码 #include<stdio.h> #include<stdlib.h> #include<string.h>…

SpringBoot 整合Dubbo

文章目录一、工程目录结构二、创建工程项目1、创建接口工程&#xff08;cw-dubbo-api&#xff09;&#xff08;1&#xff09;pom.xml&#xff08;2&#xff09;创建接口类&#xff08;LoginService&#xff09;2、创建服务提供者工程&#xff08;cw-dubbo-provider&#xff09;…

macos实现输入文件输入结束符

在clion软件中&#xff0c;执行cin>>value ,如何手动输入结束符号&#xff1f;&#xff1f;需要在debug环境下&#xff0c;然后&#xff0c;使用command D 实现此功能

2000年考研英语阅读理解文章二

文章详细解析 注意点 1.文章标题选择,查看文章中一直在重复提及的话语: 如:我们没有进化了—>标题:人类进化无路可走 知识点 ----单词 1.offspring n孩子,后代 2.Utopia n乌托邦,空想的完美境界 3.wholly adv完全地 4.comprehension n理解力 5.descendant n后代 6.mate …

Kafka Mac下安装与使用

文章目录一、下载安装二、启动Zookeeper三、启动Kafka四、创建Topic五、查看Topic六、删除Topic七、生产/消费数据八、查看消费组九、查看消费组详情一、下载安装 到 Kafka 官网下载&#xff1a;https://kafka.apache.org/downloads 下载好 tar包 后&#xff0c;执行下面命令…

C++primer第一章 开始

运算符打印endl,这是一个被称为操纵符(manipulator)的特殊值。写入endl 的效果是结束当前行&#xff0c;并将与设备关联的缓冲区(buffer)中的内容刷到设备中。缓冲刷新操作可以保证到目前为止程序所产生的所有输出都真正写入输出流中&#xff0c;而不是仅停留在内存中等待写入流…

codeforces 617A-C语言解题报告

617A题目网址 题目解析 1.输入x,能够通过1,2,3,4,5去到达x,求最小到达x的步数. 举例: 输入: 12 输出: 3 2.注意点: 要最小的步数,所以直接使用最大的5去比较判断 1)当x<5时,只需要1 2)当x>5时,如果x%50(x能整除5),只需要x/5步数,不能整除则需要x/51步数 代码 #inclu…

SpringBoot —— Bean的注入方式

文章目录1、组件注解2、Component Bean3、Import(PlaceHolderClass)快速导入一个组件4、使用Spring提供的FactoryBean注入1、组件注解 注解描述Component组件定义不清晰时候的注解Controller控制器层Service服务层Repository数据层 注&#xff1a;添加注解的类需要与启动类在…

如何保养电池

1&#xff0c;不要在低于0度和高于35度的范围下使用电池&#xff0c;尤其是高温环境下对电脑充电&#xff0c;对电池的破坏是不可逆转的。2&#xff0c;放电过于彻底或者充电过于饱和&#xff0c;也会对电池的容量造成损耗。BMS 调整电池的充放电3&#xff0c;电脑长期不用&…

codeforces 116A-C语言解题报告

116A题目网址 题目解析 1.输入n(n个循环),每一个循环-a,b;第一个循环只有b;最后一个循环只有-a;求其中在车上的最大人数? 举例: 输入: 4 0 3 2 5 4 2 4 0 输出: 6 2.注意点:因为使用count计数时,count一直在改变,所以再加入一个max变量去记录count中出现的最大数. 代码 #…

SpringBoot —— @ComponentScan注解

文章目录一、作用二、注解属性说明三、使用方式一、作用 主要是从定义的扫描路径中&#xff0c;找出标识了需要装配的类自动装配到Spring的bean容器中。 简单的说就是 ComponentScan告诉Spring从哪里找到bean&#xff0c;一旦指定了&#xff0c;Spring就会将指定的包及其下级…

硬盘 相关知识

磁盘存储数据于轨道上&#xff0c;为了防止数据不被干扰&#xff0c;轨道之间是存在间隙的。如果间隙越小存储的数据越多&#xff0c;但是对数据的写入和读取所使用的磁头是不一样的&#xff0c;写入的磁头比较宽&#xff0c;读取的磁头比较窄。叠瓦式硬盘&#xff0c;将轨道和…

Java 序列化反序列化框架比较

文章目录一、简介二、序列化框架1、JDK2、XML序列化3、JSON序列化4、Hessian5、Avro序列化6、Kyro序列化7、Protostuff三、序列化框架对比测试1、对象准备2、JDK方式3、FastJson方式4、Hessian方式5、Protostuff方式6、测试代码四、总结五、序列化应用场景六、注意事项一、简介…

C++primer 第 2 章 变量和基本类型

2.1 基本内置类型 算术类型&#xff08;arithmetictype&#xff09;和空类型&#xff08;void&#xff09;在内的基本数据类型。其中算术类型包含了字符、整型数、布尔值和浮点数。空类型不对应具体的值&#xff0c;仅用于一些特殊的场合&#xff0c;例如最常见的是&#xff0…

codeforces 58A-C语言解题报告

58A题目网址 题目解析 1.输入字符串,问如果删去其中的一些自发,能否得到hello,如果能就输出YES,否则输出NO 举例: 输入: ahhellllloou 输出: YES 2.注意点: 因为C语言没有java中的匹配字符串,则新建立一个 word[6]“hello”; 在循环中使用word去与s匹配,当匹配到了就 count…

ClickHouse 客户端命令

文章目录一、简介二、常用命令1、连接命令2、SQL语法&#xff08;1&#xff09;查看数据库列表&#xff08;2&#xff09;查看当前使用的数据库&#xff08;3&#xff09;查看数据库中表列表&#xff08;4&#xff09;创建数据库&#xff08;5&#xff09;创建表&#xff08;6&…

2000年考研英语阅读理解文章三

文章详细解析 注意点 1.当作者在文章中写到:实际问题是:我们从根本上改变了吗? 说明:我们没有发生根本上的改变,作者不同意前文中的未来派诗歌 知识点 ----单词 unhampered adj无阻碍的 finite adj有限的 ink n墨水 corresponding adj相应的,符合的 upsetting adj令人生厌…