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

news2024/11/15 11:11:48

第 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.coloradmin.cn/o/708153.html

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

相关文章

nvdiffrecmc在Windows上的配置及使用

nvdiffrecmc是NVIDIA研究院开源的项目&#xff0c;源代码地址&#xff1a;https://github.com/NVlabs/nvdiffrecmc&#xff0c;论文为《Shape, Light, and Material Decomposition from Images using Monte Carlo Rendering and Denoising》&#xff0c;使用Monte Carlo渲染和去…

为什么有些Buck-Boost芯片没有输出负压?

大家好&#xff0c;这里是大话硬件。 今天分享一篇和Buck-Boost拓扑相关的问题&#xff0c;也是在最开始接触Buck-Boost芯片时&#xff0c;就在内心产生了疑问。 在开始学习DC-DC拓扑时&#xff0c;很多资料都说&#xff0c;非隔离型的DC-DC拓扑常见的有3种&#xff0c;分别是…

C语言进阶---文件操作

1、什么是文件 磁盘上的文件是文件 但是在程序设计中&#xff0c;我们一般谈的文件有两种&#xff1a;程序文件、数据文件。&#xff08;从文件功能的角度来分类的&#xff09;。 1.1、程序文件 包括源程序文件&#xff08;后缀为.c&#xff09;&#xff0c;目标文件&#x…

若依(ruoyi-cloud)脚手架解读,一篇精通,包票上手~

视频教程传送门&#xff1a; 基于SpringCloud Alibaba技术栈&#xff0c;若依微服务版(RuoYi-Cloud)脚手架入门精解&#xff0c;保证上手那种~_哔哩哔哩_bilibili基于SpringCloud Alibaba技术栈&#xff0c;若依微服务版(RuoYi-Cloud)脚手架入门精解&#xff0c;保证上手那种~…

vscode 插件系统的运行机制!

做vscode二次开发有一段时间了&#xff0c;平时都是任务比较重&#xff0c;最近有时间做下总结&#xff0c;详细的讲解下vscode 插件系统的运行机制&#xff0c;vscode做为最受欢迎的编辑器&#xff0c;有着庞大的插件市场。其插件系统确实很复杂&#xff0c;文章很长&#xff…

构建交互式数据集展示:Gradio的Dataset模块详解

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Visual C++中的引用的具体理解

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来聊聊 Visual C中的引用。 在C中有一个引用的概念。引用就是一个变量的别名&#xff0c;它需要用另一个变量或对象来初始化自身。引用就像一个人的外号一样,例如:有一个人的名字叫诸葛大力&#xff0c;…

【压缩空气储能】非补燃压缩空气储能系统集成的零碳排放综合能源优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

软件工程作业创建表

设计表 4.按专业统计课程数量: sql SELECT Major, COUNT(*) AS Num FROM Course GROUP BY Major 5.按专业查询所有课程信息: sql SELECT * FROM Course WHERE Major 信息技术 6.统计“信息技术”专业的课程数量: sql SELECT COUNT(*) FROM Course WHERE Major 信息技术…

SIM长序列处理

原论文&#xff1a;Search-based User Interest Modeling with Lifelong Sequential Behavior Data for Click-Through Rate Prediction 主要是为了解决长序列带来的计算复杂度问题 解决方法是第一阶段先进性search&#xff0c;有softsearchhardsearch两种方式。 然后用mult-h…

SAP HANA使用SQL创建SCHEMA:

语法是 CREATE SCHEMA “<Schema_Name>” 使用图形方法创建 SAP HANA 表&#xff1a; 创建图形计算视图&#xff1a;

Spring面试题--单例bean是线程安全的吗?

Spring框架中的单例bean是线程安全的吗&#xff1f; 这个问题有一个前提 Spring框架中的bean是单例的吗&#xff1f; 答&#xff1a;是&#xff0c;我们可以通过scope注解来设置当前的bean是不是单例的 singleton : bean在每个Spring IOC容器中只有一个实例。 prototype&am…

LeetCode刷题 | 1143. 最长公共子序列、1035. 不相交的线、53. 最大子数组和

1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…

基于Python所写的今天吃什么小程序

点击以下链接获取源码资源&#xff1a; https://download.csdn.net/download/qq_64505944/87979945 《今天吃什么》程序使用说明 小程序端 启动WhatToEat/WhatToEat下的venv虚拟环境&#xff0c;运行python manage.py runserver命令启动Flask。然后打开微信开发者工具并扫码登…

MongoDB基础入门

目录 【认识MongoDB】 MongoDB的使用场景 MongoDB的结构模型 【安装MongoDB】 MacOS安装MongoDB Windows安装MongoDB 客户端连接 【认识MongoDB】 MongoDB是一个使用C语言编写的基于分布式文件存储的数据库&#xff0c;是一个开源的、高性能、高扩展、无模式的文档型…

Matlab SFM算法(两视图)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 基于运动恢复结构(SfM)是指从一组二维图像中估计场景中三维结构的过程。SfM算法被用于许多应用程序,例如3D扫描、增强现实和视觉同步定位和映射(vSLAM)。 SfM可以用许多不同的方法来计算。处理问题的方式取决于不同…

Quartz整合SpringBoot实现非持久化多任务运行

简介 java后端入门新手&#xff0c;对知识内容理解较浅&#xff0c;如文章内容有误&#xff0c;请各位大佬多多指点。本篇文章适用于对quartz有一定了解的入门新手&#xff0c;且并没有采用quartz官方的持久化方式&#xff0c;是在结合工作需求的基础上完成的quartz任务调度的…

【交换排序】手撕八大排序之快速排序和冒泡排序(超级详细)

目录 &#x1f341;一.快速排序 &#x1f340;Ⅰ.Hoare法 &#x1f347;Ⅱ.挖坑法 &#x1f34b;1.递归版本 &#x1f34a;2.关于时间复杂度 &#x1f34e;3.快速排序的优化之三数取中法 &#x1f34c;4.非递归版本&#xff08;使用栈实现&#xff09; &#x1f350;5…

什么是文件存储、对象存储、块存储?

什么是文件存储 文件存储带有文件系统&#xff0c;主要是以文件的形式存放数据&#xff0c;能将所有的目录、文件形成一个有层次的树形结构来管理&#xff0c;通过“树”不断伸展的枝丫就能找到你需要的文件。存储协议主要是NFS、CIFS等&#xff0c;以统一命名空间的形式共享一…

docker安装rabbitMQ,JAVA连接进行生产和消费,压测

1.docker安装 docker安装以及部署_docker bu shuminio_春风与麋鹿的博客-CSDN博客 2.doker安装rabbitMQ 使用此命令获取镜像列表 docker search rabbitMq 使用此命令拉取镜像 docker pull docker.io/rabbitmq:3.8-management 这里要注意&#xff0c;默认rabbitmq镜像是…