深蓝学院C++基础与深度解析笔记 第 9 章 序列与关联容器

第 9 章 序列与关联容器

1. 容器概述

A、容器: 一种特殊的类型,其对象可以放置其它类型的对象(元素)

– 需要支持的操作:对象的添加、删除、索引、遍历
– 有多种算法可以实现容器,每种方法各有利弊

B、容器分类

– 序列容器:其中的对象有序排列,使用整数值进行索引
– 关联容器:其中的对象顺序并不重要,使用键进行索引
– 适配器:调整原有容器的行为,使得其对外展现出新的类型、接口或返回新的元素
– 生成器:构造元素序列  

C、 迭代器: 用于指定容器中的一段区间,以执行遍历、删除等操作

- end()最后一个的下一个 [ , )
– 获取迭代器: ( c)begin/(  c)end ; ( c)rbegin/( c)rend: ( , ]
– 迭代器分类: 分成 5 类( category ),不同的类别支持的操作集合不同

补充:以下是这五类迭代器的分类:

  1. 输入迭代器(Input Iterator):
    输入迭代器用于从容器中读取数据元素,但只能进行单向顺序遍历,不支持对容器进行修改操作。它们通常用于遍历容器并执行算法,例如输入流迭代器。

  2. 输出迭代器(Output Iterator):
    输出迭代器用于向容器中写入数据元素,但只能进行单向顺序遍历,不支持对容器进行读取操作。它们通常用于遍历容器并执行算法,例如输出流迭代器。

  3. 前向迭代器(Forward Iterator):
    前向迭代器具有输入迭代器和输出迭代器的所有功能,可以进行单向顺序遍历,并且支持对容器进行读取和修改操作。可以多次遍历容器,但不能进行随机访问。前向迭代器通常用于单向链表等数据结构。

  4. 双向迭代器(Bidirectional Iterator):
    双向迭代器具有前向迭代器的所有功能,并且支持反向遍历容器,即可以向前或向后移动迭代器位置。双向迭代器通常用于双向链表等数据结构。

  5. 随机访问迭代器(Random Access Iterator):
    随机访问迭代器是最功能强大的迭代器类型,具有双向迭代器的所有功能,并且支持随机访问容器中的元素。可以通过指针算术运算来访问容器中的任意元素,例如使用索引、加法和减法等操作。随机访问迭代器通常用于数组、向量等连续内存存储的数据结构。

这些迭代器类别提供了不同级别的功能和灵活性,使得开发人员可以根据需求选择适当的迭代器类型来操作容器中的数据。

2. 序列容器

A、 C++ 标准库中提供了多种 序列容器模板

– array :元素个数固定的序列容器
– vector :元素连续存储的序列容器
– forward_list / list :基于链表 / 双向链表的容器
– deque : vector 与 list 的折中:双端队列
– basic_string :提供了对字符串专门的支持*
  • 需要使用元素类型来实例化容器模板,从而构造可以保存具体类型的容器。
  • 不同的容器所提供的接口大致相同,但根据容器性质的差异,其内部实现与复杂度不同。
  • 对于复杂度过高的操作,提供相对较难使用的接口或者不提供相应的接口

B、 array 容器模板: 具有固定长度的容器,其内部维护了一个内建数组,与内建数组相比提供了复制操作,提供的接口:

– 构造
– 成员类型: value_type 等
– 元素访问: [] , at , front , back , data。 []访问越界行为未定义;at()访问越界会崩溃;front指向第一个元素;data 返回一个该数组类型的指针,指向第一个元素,适用于内存连续保存的情况
– 容量相关(平凡实现): empty(优先) , size = max_size
– 填充与交换: fill , swap– 比较操作: <=>  字典序 且 类型需要完全一致
– 迭代器

fill() 实例:
在这里插入图片描述

**C、vector 容器模板:**元素可变
在这里插入图片描述

● 提供的接口:

– 与 array 很类似,但有其特殊性
– 容量相关接口: capacity (容量大小) reserve (开辟一个空间大小)shrink_to_fit  (释放空余空间)
– 附加元素接口: push_back / emplace_back(构造,可避免不必要的对象的拷贝或者移动)
– 元素插入接口: insert (插入)/ emplace (构造插入)
– 元素删除接口: pop_back(删末尾) / erase (使用迭代器删任意,迭代器失效) / clear(清空)

● 注意:

– vector 不提供 push_front / pop_front ,可以使用 insert / erase 模拟,但效率不高
– swap 效率较高
– 写操作可能会导致迭代器失效

D、list 容器模板:双向链表
在这里插入图片描述

● 与 vector 相比, list:

– 插入、删除成本较低,但随机访问成本较高
– 提供了 pop_front / splice () 把第二个参数复制给第一个参数后面,等接口
– 写操作通常不会改变迭代器的有效性,删除可变能导致迭代器失效

E、forward_list 容器模板:单向链表

– 目标:一个成本较低的线性表实现
– 其迭代器只支持递增操作,因此无 rbegin/rend
– 不支持 size :和list不同,没有使用专门的计数的内存,精简为上
– 不支持 pop_back / push_back
– XXX_after 操作

F、deque容器模板: vector 与 list 的折衷:双端队列

– push_back / push_front 速度较快
– 在序列中间插入、删除速度较慢

G、basic_string 容器模板: 实现了字符串相关的接口

– 使用 char 实例化出 std::string
– 提供了如 find , substr 等字符串特有的接口
– 提供了数值与字符串转换的接口 to_string()转字符串   stoi()整数
– 针对短字符串的优化( )

3. 关联容器

● 使用键进行索引
– set / map / multiset / multimap
– unordered_set / unordered_map / unordered_multiset / unordered_multimap
●set / map / multiset / multimap 底层使用红黑树实现,元素通常不是连续存储的

● unordered_xxx 底层使用 hash 表实现

A、set
在这里插入图片描述

– 通常来说,元素需要支持使用 < 比较大小
– 或者采用自定义的比较函数来引入大小关系
– 插入元素: insert / emplace / emplace_hint(能减少比较次数,如果是错误的提示会大大增大耗时),不能重复插入 
– 删除元素: erase
– 访问元素: find / c:查找类似于二分法
– 修改元素: extract 

● 注意: set 迭代器所指向的对象是 const 的,不能通过迭代器修改元素

补充:emplace_hint
std::setemplace_hint 方法用于在指定位置的提示位置处插入元素。它的语法如下:

iterator emplace_hint(const_iterator hint, Args&&... args);

参数说明:

  • hint:一个迭代器,表示插入位置的提示位置。在此位置附近查找插入点,以保持有序性。如果提供的提示位置是正确的,可以提高插入的效率。
  • args:要插入的元素的构造参数。这些参数将被传递给元素类型的构造函数。

返回值:一个迭代器,指向插入的元素。

以下是 emplace_hint 方法的示例用法:

#include <iostream>
#include <set>int main() {std::set<int> mySet = {10, 20, 30, 40, 50};// 使用 emplace_hint 在指定位置的提示位置处插入元素auto hint = mySet.find(30); // 提示位置为元素值为 30 的位置if (hint != mySet.end()) {mySet.emplace_hint(hint, 35);}// 输出集合中的元素for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

输出结果:

10 20 30 35 40 50

在上面的示例中,我们首先找到值为 30 的元素的迭代器作为插入的提示位置,然后使用 emplace_hint 在提示位置处插入值为 35 的元素。最后,我们输出了修改后的集合内容,可以看到新元素成功插入并保持了集合的有序性。

B、map

在这里插入图片描述

– 树中的每个结点是一个 std::pair< ,  >
– 键 (pair.first) 需要支持使用 < 比较大小
– 或者采用自定义的比较函数来引入大小关系
– 访问元素: find / contains / [] / at(访问越界会抛出异常)

元素不能重复: 在 std::map 中插入一个已有键值对将不会导致键的重复插入。在 std::map 中,每个键都是唯一的,因此当你尝试插入一个已存在的键值对时,插入操作不会成功。

● 注意
– map 迭代器所指向的对象是 std::pair < , >,其键是 const 类型
– [ ] 操作不能用于常量对象

C、 multiset / multimap
与 set / map 类似,但允许重复键

  • 元素访问:
    find() 返回首个查找到的元素
    在这里插入图片描述
    ps: 此时,ptr指向第二个 1 元素

count() 返回元素个数
lower_bound() / upper_bound() / equal_range() 返回查找到区间的元素
在这里插入图片描述
返回1

D、 unordered_set / unordered_map / unordered_multiset / unordered_multimap
底层通过哈希表实现,哈希表示意图:
在这里插入图片描述

– 与 set / map 相比查找性能更好,但插入操作一些情况下会慢(vector重新分配空间时)
– 其键需要支持两个操作- 转换为 hash 值- 判等
– 除 ==!= 外,不支持容器级的关系运算-==, != 速度较慢,在内存上需要进行额外的处理,使得两个Map可以比较
– 自定义 hash 与判等函数

4. 适配器与生成器

在 C++ STL 中,适配器(Adapter)是一种容器或迭代器的包装器,它们提供了额外的功能或改变了原始容器或迭代器的行为,使其适应不同的需求或接口。适配器可以分为两种类型:容器适配器和迭代器适配器。适配器的目的是在不修改原始容器或迭代器的情况下,提供了一种新的接口或功能。它们通过封装现有的组件,使其更加灵活和适应特定的需求。

容器适配器:
A、类型适配器
1、basic_string_view ( C++17 )

● 可以基于 std::string , C 字符串`char*` ,迭代器构造
● 提供成本较低的操作接口, 不要传递引用

● basic_string_view ,返回的是一个常量类型,不可进行写操作

2、 span ( C++20 )
● 可基于 C 数组、 array 等构造
可读写

B、接口适配器
– stack / queue / priority_queue
deque
– 对底层序列容器进行封装,对外展现栈、队列与优先级队列的接口
– priority_queue 在使用时其内部包含的元素需要支持比较操作

C、 数值适配器 (c++20) : std::ranges::XXX_view, std::ranges::views::XXX, std::views::XXX
使用括号view()或者 | view

– 可以将一个输入区间中的值变换后输出
– 数值适配器可以组合,引入复杂的数值适配逻辑

D、 生成器 (c++20)

– std::ranges::itoa_view, std::ranges::views::itoa, std::views::itoa
– 可以在运行期生成无限长或有限长的数值序列

在这里插入图片描述

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

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

相关文章

Redis的高可用与持久化

目录 一、Redis 高可用1. 持久化2. 主从复制3. 哨兵4. 集群(cluster) 二、Redis 持久化方式1. 持久化的功能2. 持久化的方式 三、RDB 持久化1. 触发条件2.执行流程3. 启动时加载 四、AOF持久化1.开启 AOF2. 执行流程2.1 命令追加2.2 文件写入&#xff08;write&#xff09;和文…

【机器学习】——续上:卷积神经网络(CNN)与参数训练

目录 引入 一、CNN基本结构 1、卷积层 2、下采样层 3、全连接层 二、CNN参数训练 总结 引入 卷积神经网络&#xff08;CNN&#xff09;是一种有监督深度模型框架&#xff0c;尤其适合处理二维数据问题&#xff0c;如行人检测、人脸识别、信号处理等领域&#xff0c;是带…

threejs动画

个人博客地址: https://cxx001.gitee.io 前面我们所用的模型大都是静态的&#xff0c;没有动画&#xff0c;没有生命。这节我们将赋予它们生命。 动画本质是通过改变物体的旋转、缩放、位置、材质、顶点、面以及其它你所能想到的属性来实现的。这些其实在前面章节示例里或多或…

win11,win10睡眠自动被唤醒部分总结

网上查了很多的解决方法&#xff0c;试了关闭 启用快速启动&#xff0c;大致有几点 1. powercfg /lastwake cmd命令行输入powercfg /lastwake&#xff0c;可以查询最后一次被哪个设备唤醒 2. PowerCfg -DEVICEQUERY wake_armed 也是命令行输入&#xff0c;查询所有可以唤醒电…

基于Thinkphp6框架全新UI的AI网址导航系统源码

2023全新UI的AI网址导航系统源码&#xff0c;基于thinkphp6框架开发的 AI 网址导航是一个非常实用的工具&#xff0c;它能够帮助用户方便地浏览和管理自己喜欢的网站。 相比于其他的 AI 网址导航&#xff0c;这个项目使用了更加友好和易用的 ThinkPHP 框架进行搭建&#xff0c…

学习系统编程No.25【核心转储实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/16/8:39&#xff0c;实训课中&#xff0c;大一下学期最后有课的一天&#xff0c;还有两天就要期末考啦&#xff01;目前什么都还没有复习&#xff0c;不到星期天晚上&#xff0c;咱不慌&#xff0c;小小挂科&#xff0c;岂能拦得…

系列二、Maven下载安装配置

一、下载 链接&#xff1a;https://pan.baidu.com/s/1BvwLzAk9kRSP-daxSYe4Vw?pwdyyds 提取码&#xff1a;yyds 二、安装 第一步&#xff1a;下载安装包 第二步&#xff1a;解压至安装目录&#xff0c;例如 第三步&#xff1a;配置settings.xml&#xff08;主要配置maven本…

STM32F407 滴答定时器

介绍STM32F407滴答定时器配置方法、使用方式&#xff0c;封装延时函数得到精确的时间。 【1】介绍滴答定时器的章节 STM32F407参考手册中第10章介绍了滴答定时器的校准值。 M4权威指南介绍滴答定时器的章节&#xff0c;M3权威指南中与M4权威指南中的介绍一样。 【2】滴答定时…

Linux--打印内容或者插入内容:echo

语法&#xff1a; echo 内容 作用&#xff1a;打印内容到显示器echo 内容 > 不存在的文件 作用&#xff1a;文件创建&#xff0c;并将内容插入新创建的文件中echo 内容 > 存在的文件 作用&#xff1a;覆盖文件原有的内容 echo 内容 >> 存在的文件 作用&#xff1a…

Tdengine 时序数据库-安装与客户端连接

使用 TDengine 时序数据库的版本是 2.4.0.0 使用的安装RPM的安装方便安装 TDengine-server-2.4.0.0-Linux-x64.rpm 1. 安装指令: rpm -ivh TDengine-server-2.4.0.0-Linux-x64.rpm [rootnode3 server]# rpm -ivh TDengine-server-2.4.0.0-Linux-x64.rpm Verifying... …

Java对称与非对称加密解密(AES与RSA)

尽可能预想所有残酷的可能性、因为现实永远让你无法预警,而且又吝于给人慈悲。——富坚义博 今天我们讨论一下秘钥这个东西 一、对称加密技术与非对称加密技术简述 加密技术可以分为对称与非对称两种。 对称加密、解密即加密与解密用的是同一把秘钥,常用的对称加密技术有DES,A…

微服务springcloud 10.config配置中心框架和rabbitmq的安装

config配置中心的作用&#xff1a;项目的yml 配置文件保存到 git 服务器&#xff0c;例如 github.com 或 gitee.com 微服务启动时&#xff0c;从服务器获取配置文件 1.新建 “Project”,命名为 config。注意这里的不是maven项目&#xff0c;而是project 2.将sp02,sp03,sp04,s…