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,一经查实,立即删除!

相关文章

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;元素是关键字_值…

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;…

C++primer第一章 开始

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

硬盘 相关知识

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

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

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

SpringBoot 集成Mybatis

文章目录一、创建SpringBoot项目二、添加Mybatis相关依赖三、数据源配置四、创建事务的模型实体类五、创建和数据库交互联系的映射关系类六、创建业务接口和实现类七、创建控制器类八、请求验证一、创建SpringBoot项目 如何创建详见&#xff1a;IDEA 创建 SpringBoot 项目 二、…

C++primer 第 3 章 字符串、向量和数组 3.1 命名空间的using声明 3.2标准库类型string

引言 除了第2章介绍的内置类型之外,C语言还定义了 -个内容丰富的抽象数据类型库。其中,string和 vector是两种最重耍的标准库类型&#xff0c;前者支持可变长字符串&#xff0c;后者则 表示可变长的集合。还有…种标准库类型是迭代器&#xff0c;它是string和vector的配套类型…

C++primer 第 3 章 字符串、向量和数组 3 . 3 标准库类型vector

标准库类型vector表示对象的集合&#xff0c;其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引&#xff0c;索引用于访问对象。因为vector"容纳着”其他对象&#xff0c;所以它也常被称作容器(container).第 II部将对容器进行更为详细的介绍。 要想使用…

SpringBoot AOP切面实现

文章目录一、AOP简介二、AOP体系与概念三、AOP实例1、创建SpringBoot工程2、添加依赖3、AOP相关注解3.1、Aspect3.2、Pointcut3.2.1、execution()3.2.2、annotation()3.3、Around3.4、Before3.5、After3.6、AfterReturning3.7、AfterThrowing一、AOP简介 AOP&#xff08;Aspec…

英语口语-文章朗读Week8 Friday

文章 It is a phenomenon that people are losing trust in each other in today’s society. Some people become selfish,and for interest, they are likely to betray their colleagues,friends, and even their relatives. They tend to cater to those who can benefit …

C++primer 第 3 章 字符串、向量和数组 3 . 4 迭代器介绍

3.4迭代器介绍 我们已经知道可以使用下标运算符来访问string对象的字符或vector对象的元素&#xff0c;还有另外一种更通用的机制也可以实现同样的目的&#xff0c;这就是迭代器&#xff08;iterator&#xff09;。在第II部分中将要介绍&#xff0c;除了vector之外&#xff0c…

英语口语-文章朗读Week9 TuesDay

朗读文章 People living in ancient times had no alternative but to do housework manually. They fire the wood when they cook,they hand wash clothes with hands; they sweep the floor with brooms. Now, modern inventions come as a great relief to people. We co…

C++primer 第 3 章 字符串、向量和数组 3 . 5 数组

3.5数组 数组是一种类似于标准库类型vector&#xff08;参见3.3节&#xff0c;第86页&#xff09;的数据结构&#xff0c;但是在性能和灵活性的权衡上又与vector有所不同。与vector相似的地方是&#xff0c;数组也是存放类型相同的对象的容器&#xff0c;这些对象本身没有名字…

C++primer 第 4 章 表达式 4.1基础 4 . 2 算术运算符 4 .3 逻辑和关系运算符 4 . 4 赋值运算符 4 .5 递增和递减运算符 4.6成员访问运算符

表达式由一个或多个运算对象(operand)组成&#xff0c;对表达式求值将得到一个结果(result)字面值和变量是最简单的表达式(expression),其结果就是字面值和变量的值。把一个运算符(operator)和一个或多个运算对象组合起来可以生成较复杂的表达式 4.1基础 有几个基础概念对表达…

codeforces 266B-C语言解题报告

266B题目网址 题目解析 输入n,t,排队情况s,输出第t次循环后,排队情况 举例: 输入: 5 1 BGGBG 输出: GBGGB 2.输入的n代表排队的人数,t代表整个循环t次之后再输出结果 3.注意点: 使用while()大循环去控制t次的循环,使用for()内层循环去遍历整个字符串 如果if(s[j]‘B’&…

英语口语-文章朗读Week9 Wednesday

英语文章 Birds of the same species flock together&#xff0c; People tend to look for someone like themselves to be friends. But having the same interests is not the only standard when we are seeking friends. In most cases, especially for adults, people l…

C++primer 第 4 章 表达式 4.7条件运算符 4.8位运算符 4.9 sizeof运算符 4.10逗号运算符 4.11类型转换 4 . 1 2 运算符优先级表

4.7条件运算符 条件运算符(?&#xff1a;)允许我们把简单的if else逻辑嵌入到单个表达式当中&#xff0c;条件运算符按照如下形式使用&#xff1a;cond ? expr1 : expr2;其中cond是判断条件的表达式&#xff0c;而expr1和expr2是两个类型相同或可能转换为某个公共类型的表达…

Git 之 git tag标签使用

目录一、简介二、本地tag操作1、创建tag标签&#xff08;1&#xff09;创建轻量标签&#xff08;2&#xff09;创建附注标签2、查看tag标签&#xff08;1&#xff09;查看标签列表&#xff08;2&#xff09;查看标签提交信息&#xff08;3&#xff09;在提交历史中查看标签3、删…

C++primer 第 5 章语句 5.2语句作用域 5.3条件语句 5 . 4 迭代语句 5.5跳转语句 5.6 try语句块和异常处理

5 . 1 简单语句 C语言中的大多数语句都以分号结束&#xff0c;一个表达式&#xff0c;比如ival 5 , 末尾加上分号就变成了表达式语句(expression statement)。表达式语句的作用是执行表达式并丢弃掉求值结果&#xff1a;ival 5&#xff1b; // 一条没什么实际用处的表达式语…