《C++ Primer Plus》第16章:string类和标准模板库(8)
关联容器
关联容器(associative container)是对容器概念的另一个改进。关联容器将值与键关联在一起,并使用键来查找值。例如,值可以表示雇员信息(如姓名、地址、办公室号码、家庭电话和工作电话、健康计划等)的结构,而键可以是唯一的员工编号。为获取雇员信息,程序将使用键查找雇员结构。前面说过,对于容器 X,表达式 X::value_type 通常指出了存储在容器中的值类型。对于关联容器来说,表达式 X::key_type 指出了键的类型。
关联容器的优点在于,它提供了对元素的快速访问。与序列相似,关联容器也允许插入新元素,但不能指定元素的插入位置。原因是关联容器通常有用于确定数据放置位置的算法,以便能够快速检索信息。
关联容器通常是使用某种树实现的。树是一种数据结构,其根节点链接到一个或两个节点,而这些节点又链接到一个或两个节点,从而形成分支结构。像链表一样,节点使得添加或删除数据项比较简单;但相对于链表,树的查找速度更快。
STL提供了4种关联容器:set、multiset、map 和 multimap。前两种是在头文件 set(以前分别为 set.h 和 multiset.h)种定义的,而后两种是在头文件 map(以前分别为 map.h 和 multimap.h)中定义的。
最简单的关联容器是 set,其值类型与键相同,键是唯一的,这意味着集合中不会有多个相同的键。确实,对于 set 来说,值就是键。multiset 类似于 set,只是可能有多个值的键相同。例如,如果键和值的类型为 int,则 multiset 对象包含的内容可以是 1、2、2、2、3、5、7、7。
在 map 中,值与键的类型不同,键是唯一的,每个键只对应一个值。multimap 与 map 相似,只是一个键可以与多个值相关联。
有关这些类型的信息很多,无法在本章全部列出(但附录G列出了方法),这里只介绍一个使用 set 的简单例子和一个使用 multimap 的简单例子。
-
set 示例
STL set 模拟了多个概念,它是关联集合,可反转,可排序,且键是唯一的,所以不能存储多个相同的值。与 vector 和 list 相似,set 也使用模板参数来指定要存储的值类型:set<string> A; // a set of string objects第二个模板参数是可选的,可用于指示用来对键进行排序的比较函数或对象。默认情况下,将使用模板 less<> (稍后将讨论)。老式 C++ 实现k额能没有提供默认值,因此必须显示指定模板参数:
set<string, less<string> > A; // older implementation请看下面的代码:
const int N = 6; string s1[N] = {"buffoon", "thinkers", "for", "heavy", "can", "for" }; set<string> A(s1, s1 + N); // initialize set A using a range from array ostream_iterator<string, char> out(cout, " "); copy(A.begin(), A.end(), out);与其他容器相似,set 也有一个将迭代器区间作为参数的构造函数。这提供了一种将集合初始化为数组内容的简单方法。请记住,区间的最后一个元素是超尾,s1+N 指向数组 s1 尾部后面的一个位置。上述代码片段的输出表明,键是唯一的(字符串"for"在数组中出现了2次,但在集合中值出现了1次),且集合被排序:
buffoon can for heavy thinkers数学为集合定义了一些标准操作,例如,并集包含两个集合合并后的内容。如果两个集合包含相同的值,则这个值在并集中只出现一次,这是因为键是唯一的。交集包含两个集合都有的元素。两个集合的差是第一个集合减去两个集合都有的元素。
STL 提供了支持这些操作的算法。它们是通用的函数,而不是方法,因此并非只能用于 set 对象。然而,所有 set 对象都自动满足使用这些算法的先决条件,即容器是经过排序的。 set_union() 函数接受 5 个迭代器参数。前两个迭代器定义了第一个集合的区间,接下来的两个定义了第二个集合区间,最后一个迭代器是输出迭代器,指出将结果集合复制到什么位置。例如,要显示集合 A 和 B 的丙级,可以这样做:
set_union(A.begin(), A.end(), B.begin(),B.end(),ostream_iterator<string, char> out(cout, " "));假设要将结果放到集合 C 中,而不是显示它,则最后一个参数应是一个指向C的迭代器。显而易见的选择是 C.begin(),但它不管用,原因有两个。首先,关联集合将键看作常量,所以C.begin() 返回的迭代器是常量迭代器,不能用作输出迭代器。不直接使用 C.begin() 的第二个原因是,与 copy() 相似,set_union() 将覆盖容器中已有的数据,并要求容器有足够的空间容纳新信息。C 是空的,不能满足这种要求。但前面讨论的模板 insert_iterator 可以解决这两个问题。前面说过,它可以将复制转换为插入。另外,它还模拟了输出迭代器概念,可以用它将信息写入容器。因此,可以创建一个匿名 insert_iterator,将信息复制给 C。前面说过,其构造函数将容器名称和迭代器作为参数:
set_uniong(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> >(C. C.begin() );函数 set_intersection() 和 set_difference() 分别查找交集和获得两个集合的差,它们的接口与 set_union() 相同。两个有用的方法是 lower_bound() 和 upper_bound()。方法 lower_bound() 将键作为参数并返回一个迭代器,该迭代器指向集合中第一个不小于键参数的成员。同样,方法 upper_bound() 将键作为参数,并返回一个迭代器,该迭代器指向集合中第一个大于键参数的成员。例如,如果有一个字符串集合,则可以用这些方法获得一个这样的区间,即包含集合中从 “b” 到 “f” 的所有字符串。
因为排序决定了插入的位置,所以这种类包含只指定要插入的信息,而不指定位置的插入方法。例如,如果 A 和 B 是字符串集合,则可以这样做:
string s("tennis"); A.insert(s); // insert a value B.insert(A.begin(), A.end() ); // insert a range下面的程序演示了集合的这些用途:
// setops.cpp -- some set operations #include <iostream> #include <string> #include <set> #include <algorithm> #include <iterator>int main(){using namespace std;const int N = 6;string s1[N] = {"buffoon", "thinkers", "for", "heavy", "char", "for"};string s2[N] = {"metal", "any", "food", "elegant", "deliver", "for"};set<string> A(s1, s1+N);set<string> B(s2, s2+N);ostream_iterator<string, char> out(cout, " ");cout << "Set A: ";copy(A.begin(), A.end(), out);cout << endl;cout << "Set B: ";copy(B.begin(), B.end(), out);cout << endl;cout << "Union of A and B:\n";set_union(A.begin(), A.end(), B.begin(), B.end(), out);cout << endl;cout << "Intersection of A and B:\n";set_intersection(A.begin(), A.end(), B.begin(), B.end(), out);cout << endl;cout << "Difference of A and B:\n";set_difference(A.begin(), A.end(), B.begin(), B.end(), out);cout << endl;set<string> C;cout << "Set C:\n";set_union(A.begin(),A.end(),B.begin(),B.end(),insert_iterator<set<string> >(C,C.begin()));copy(C.begin(),C.end(),out);cout << endl;string s3("grungy");C.insert(s3);cout << "Set C after insertion:\n";copy(C.begin(), C.end(), out);cout << endl;cout << "Showin a range:\n";copy(C.lower_bound("ghost"),C.upper_bound("spook"),out);cout << endl;return 0; }下面是程序的输出:
Set A: buffoon char for heavy thinkers Set B: any deliver elegant food for metal Union of A and B: any buffoon char deliver elegant food for heavy metal thinkers Intersection of A and B: for Difference of A and B: buffoon char heavy thinkers Set C: any buffoon char deliver elegant food for heavy metal thinkers Set C after insertion: any buffoon char deliver elegant food for grungy heavy metal thinkers Showin a range: grungy heavy metal和本章大多数示例一样,该程序在处理名称空间 std 时采取了偷懒的方式:
using namespace std;这样做旨在简化表达方式。这些示例使用了名称空间中非常多的元素,如果使用 using 声明或作用域运算符,代码将变得混乱:
std::set<std::string> B(s2, s2+N) std::ostream_iterator<std::string, char> out(std::cout, " "); std::cout << "Set A: "; std::copy(A.begin(), A.end(), out); -
multimap 示例
与 set 相似,multimap 也是可反转的、经过排序的关联容器,但键和值的类型不同,且同一个键可能与多个值相关联。
基本的 multimap 声明使用模板参数指定键的类型和存储的值类型。例如,下面的声明创建一个 multimap 对象,其中键类型为 int,存储的值类型为 string:multimap<int, string> codes;第3个模板参数是可选的,指出用于对键进行排序的比较函数或对象。在默认情况下,将使用模板less<> (稍后将讨论),该模板将键类型作为参数。老式 C++ 实现可能要求显示指定该模板参数。
为将信息结合在一起,实际的值类型将键类型和数据类型结合为一对。为此,STL 使用模板类pair<class T, class U> 将这两种值存储到一个对象中。如果 keytype 是键类型,而 datatype 是存储的数据类型,则值类型为 pair<const keytype, datatype>。例如,前面声明的 codes 对象的值类型为 pair<const int, string>。
例如,假设要用区号作为键来存储城市名(这恰好与 codes 声明一致,它将键类型声明为 int,数据类型声明为 string),则一种方法是创建一个 pair,再将它插入:
pair<const int, string> item(213, "Los Angeles"); codes.insert(item);也可使用一条语句创建匿名 pair 对象并将它插入:
codes.insert(pair<const int, string> (213, "Los Angeles"));因为数据项是按键排序的,所以不需要指出插入位置。
对于 pair 对象,可以使用 first 和 second 成员来访问其两个部分了:pair<const int, string> item(213, "Los Angeles"); cout << item.first << ' ' << item.second << endl;如何获得有关 multimap 对象的信息呢?成员函数 count() 接受键作为参数,并返回具有该键的元素数目。成员函数 lower_bound() 和 upper_bound() 将键作为参数,且工作原理与处理 set 时相同。成员函数 equal_range() 用键作为参数,且返回两个迭代器,它们表示的区间与该键匹配。为返回两个值,该方法将它们封装在一个 pair 对象中,这里 pair 的两个模板参数都是迭代器。例如,下面的代码打印 codes 对象中区号为 718 的所有城市:
pair<multimap<KeyType, string>::iterator, multimap<KeyType, string>::iterator> range= cods.equal_range(718); cout << "Cities with area code 718:\n"; std::multimap<KeyType, std::string>::iterator it; for (it - range.first; it != range.seconde; ++it){cout << (*it).second << endl; }在声明中可使用 C++11 自动类型推断功能,这样代码将简化为如下所示:
auto range = codes.equal_range(718); cout << "Cities with area code 718:\n"; for (auto it = range.first; it != range.second; ++it){cout << (*it).second << endl; }下面的程序演示了上述大部分计数,它也是用 typedef 来简化代码:
// multimap.cpp -- use a multimap#include<iostream> #include<string> #include<map> #include<algorithm>typedef int KeyType; typedef std::pair<const KeyType, std::string> Pair; typedef std::multimap<KeyType, std::string> MapCode;int main(){using namespace std;MapCode codes;codes.insert(Pair(415,"San Francisco"));codes.insert(Pair(510, "Oakland"));codes.insert(Pair(718, "Brooklyn"));codes.insert(Pair(718, "Staten Island"));codes.insert(Pair(415, "San Rafael"));codes.insert(Pair(510, "Berkeley"));cout << "Number of cities with area code 415: "<< codes.count(415) << endl;cout << "Number of cities with area code 718: "<< codes.count(718) << endl;cout << "Number of cities with area code 510: "<< codes.count(510) << endl;cout << "Area Code City\n";MapCode::iterator it;for(it = codes.begin(); it!=codes.end(); ++it){cout << " " << (*it).first << " "<< (*it).second << endl;}pair<MapCode::iterator, MapCode::iterator> range= codes.equal_range(718);cout << "Cities with area code 718:\n";for (it = range.first; it!=range.second; ++it){cout << (*it).second << endl;}return 0; }下面的是程序的输出:
Number of cities with area code 415: 2 Number of cities with area code 718: 2 Number of cities with area code 510: 2 Area Code City415 San Francisco415 San Rafael510 Oakland510 Berkeley718 Brooklyn718 Staten Island Cities with area code 718: Brooklyn Staten Island
无序关联容器(C++11)
无序关联容器是对容器概念的另一种改进。与关联容器一样,无序关联容器也将值与键关联起来,并使用键来查找值。但底层的差别在于,关联容器是基于树结构的,而无序关联容器是基于数据结构哈希表的,这旨在提高添加和删除元素的速度以及提高查找算法的效率。有4种无序关联容器,它们是 unordered_set、unordered_multiset、unordered_map 和 unordered_multimap,将在附录 G 更详细地介绍。
相关文章:
《C++ Primer Plus》第16章:string类和标准模板库(8)
关联容器 关联容器(associative container)是对容器概念的另一个改进。关联容器将值与键关联在一起,并使用键来查找值。例如,值可以表示雇员信息(如姓名、地址、办公室号码、家庭电话和工作电话、健康计划等ÿ…...
Linux安装达梦8数据库
Linux安装达梦8数据库 服务器系统:centos7 数据库版本:达梦8 先获取安装包:https://eco.dameng.com/download/?_blank 选择相应版本下载,下载完解压之后会得到一个iso文件,把他上传到服务器上,建议上传到/opt目录下…...
[数据库]初识数据库
●🧑个人主页:你帅你先说. ●📃欢迎点赞👍关注💡收藏💖 ●📖既选择了远方,便只顾风雨兼程。 ●🤟欢迎大家有问题随时私信我! ●🧐版权:本文由[你帅…...
Redis的缓存雪崩、击穿、穿透和解决方案
2.5 缓存穿透问题的解决思路 缓存穿透 :缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种: 缓存空对象 优点:实现简单,维护…...
52000000
选择题(共52题,合计52.0分) 1. 敏捷团队在项目执行过程中会用到一种叫做“看板”的可视化工具,它可显示WIP, 帮助识别瓶颈和过度承诺, 从而使团队能够优化工作流。请从下列选项中选择WIP的最佳解释?() A 等待初步加工的材料的库存 B 目前正…...
内网资源探测
✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆 🔥系列专栏 :内网安全 📃新人博主 :欢迎点赞收藏关注,会回访! 💬舞台再大,你不上台,永远是…...
Java后端内部面试题(前一部分)
面试题 基础篇 1、Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象(Java最重要的特性,让程序耦合度更低,内聚性更高) 2、面向对象和面向过程的区别 面向过程:是分析解决问题的步骤,然后用函数把…...
关于如何抄引擎源码
前两天,后台有网友发私信给我,问我如何抄引擎源码。我一愣,感觉像吃饭喝水一样自然。 抄源码的好处就不说了,抄之前不懂的内容,抄完后就懂了,至少懂一部分了。当然也可以只读不抄,不过ÿ…...
差分模拟信号转单端输出电路设计
需求分析: 1.差分输入0~16V -Vpp电压量; 2.输入频率0~1.2KHz; 3.单端对应输出0~3V的模拟量; 4.输出频率对应0~1.2KHz; 5.供电范围3~5V。 针对以上需求,设计如下图所示电路。 1.电路功能: …...
Java中的clone方法
注解定义: 注解是一种注释机制,它可以注释包、类、方法、变量、参数,在编译器生成类文件时,标注可以被嵌入到字节码中。注解的分类:内置注解Override :重写方法,引用时没有该方法时会编译错误public class …...
数据结构—二叉树、完全二叉树的性质
# 1 若一棵度为4的树中度为1、2、3、4的结点个数分别为4、3、2、2,则该树的总结点个数是多少? 正确答案: 答案:结点总数nn0n1n2n3n4,又由于除根结点外,每个结点都对应一个分支,所以总的分支数等…...
JDBC编程复习
文章目录JDBC1.概念2.原理3. 如何使用JDBC编程1. 下载mysql的jdbc驱动2. 项目中引入驱动4. JDBC使用1. 和数据库建立连接2.获取连接3. Statement对象4. 释放资源JDBC 1.概念 JDBC,即Java Database Connectivity,java数据库连接。是Java提供的API用来执行SQL语句&a…...
c++基础入门二
一、数组的引用int main() {int a 10, b 20;int ar[10] { 1,2,3,4,6,7 };int& x ar[0];int& p[5] ar;//errorint(&p)[10] ar;//引用整个数组的大小sizeof(ar)int(*p)[10] &ar;//typesize表示整个数组//只有在这三种情况下代表整个数组,其他情…...
企业数字化转型的产品设计思路
数字化转型的核心是全面重塑企业的管理模式和经营模式,是迈向数字经济时代的方式。一、到底什么是数字化转型?数字化转型并不神秘。数字化转型是一种经营方式、一种经营理念,是将企业相关的人、物料、设备、资金等要素进行系统运转࿰…...
Linux日志分析常用命令
一:常用命令1、tail参数: tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ] 参数说明: -f 该参数用于监视File文件增长。 -c Number 从 Number 字节位置读取指定文件 -n Number 从 Number 行位置读取指…...
Allegro如何使用Snake命令走蛇形线操作指导
Allegro如何使用Snake命令走蛇形线操作指导 在做PCB设计的时候,遇到不规则BGA的时候,蛇形走线是惯用的走线方式,类似下图 Allegro支持蛇形走线,具体操作如下 首先把过孔打好,尽量上下左右间距一致,不容易出现偏差,如下图在Command命令栏下方输入snake,然后回车...
在 Eclipse 中创建 Maven 项目
1.在 Eclipse 中配置 MavenEclipse 中默认自带 Maven 插件,但是自带的 Maven 插件不能修改本地仓库,所以通常我们不使用自带的 Maven ,而是使用自己安装的,在 Eclipse 中配置 Maven 的步骤如下: 1) 点击 Eclipse 中的 …...
flex 布局相关属性的使用
简单概述 为元素添加 display:flex; 的属性后,当前元素被视为弹性布局的盒子容器(box),其子元素被视为弹性布局项目(item)。item 会在 box 内灵活布局,解决了对齐、分布、尺寸等响应式问题。 演示 demo <template><div class&quo…...
【C++】类和对象(第一篇)
文章目录1. 面向过程和面向对象初步认识2.类的引入3.类的定义3.1 类的两种定义方式3.2 成员变量命名规则建议4. 类的访问限定符及封装4.1 访问限定符4.2 封装5. 类的作用域6. 类的实例化7. 类对象模型7.1 类对象大小的计算7.2 类对象的存储方式猜测7.3 结构体内存对齐规则复习8…...
springboot 接入websocket实现定时推送消息到客户端
目录说明代码实现说明 如标题,举例需求场景: 前端与后端websocket连接上后,多用户登录,后端根据不同用户定时发消息给前端用于展示 代码实现 1、 <dependency><groupId>org.springframework.boot</groupId>…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...
