【C++】12.序列与关联容器[深蓝学院C++第10章]
一.容器概述
一种特殊的类型,其对象可以放置其他类型的对象(元素)
需要支持的操作:通常包括添加、删除、索引、遍历
有多种算法可以实现容器,每种方法各有利弊
1.1 分类
序列容器:其中的对象有序排列,一般使用下标进行索引
关联容器:其中的对象顺序并不重要,使用键进行索引
适配器:调整原有容器的行为,使其对外展现出新的类型、接口或返回新的元素
生成器:构造元素序列
1.2 迭代器
用于指定容器中的一段区间,以执行遍历、删除等操作
获取迭代器:(c)begin/(c)end,带c的是const。rbegin和rend,逆向遍历
分为5类、5种categary,不同的类别支持的操作集合不同
(1)input iterator
(2)output interator
(3)forward interator:兼具input和output
(4)bidirectional iterator,双向
(5)random access iterator,可以++、--
二.序列容器
2.1 标准库提供的序列容器
(1)array,元素固定的序列容器
(2)vector,元素连续存储的序列容器
(3)forward_list/list,基于链表、双向链表的容器
(4)deque,vector和list的这种,双向队列
(5)basic_string,提供了对字符串专门的支持
需要指定元素类型来实例化
不同的容器所提供的接口大致相同,容器不同其内部复杂度不同
对于复杂度过高的操作,提供相对较难使用的接口或者不提供相应的接口
2.2 array
具有固定长度的容器,其内部维护了一个内建数组,与内建数组相比提供了复制
接口:
(1)构造,std::array<int,用户指定size> a = {集合初始化};
(2)读取成员类型:value_type等
(3)元素访问,[]、at、front、back、data(传入数组指针)
(4)容器相关:empty、size、max_size
(5)填充和交换:fill、swap
(6)比较操作:<=> spaceship operator,用来返回比较结果的枚举值,按照字典序来比较
(7)迭代器,begin、end
2.3 vector
元素可变
接口:
(1)与array相似
(2)容量相关的:capacity容量、reserve翻转、shrink_to_fit削减多余的空间
(3)附加元素接口:push_back、emplace_back
(4)元素插入接口:insert、emplace
(5)元素删除接口:pop_back、erase、clear
注意:
(1)vector不提供push_front、pop_front,可以使用insert(造成后挪)、erase(造成前挪)模拟但比较慢
(2)swap效率较高
(3)写操作可能导致迭代器失效
2.4 list
双向链表
与vector相比,list:
(1)插入、删除成本较低,但随机访问成本较高
(2)提供了pop_front、splice等接口,splice可以把某list一次性挪入另外一个list
(3)写操作通常不会改变迭代器的有效性
forward_list的特性:
(1)单向链表,一个成本比较低的线性表实现
(2)其迭代器只支持递增操作,无rbegin和rend
(3)不支持size
(4)不支持pop_back和push_back
(5)xxx_after操作,只能在某个元素后面作一系列操作
2.5 deque
双向队列/双端队列,是vector和list的折中
特性:
(1)push_back/push_front速度较快
(2)在序列中间插入、删除较慢
2.6 basic_string
实现了字符串相关的接口
特性:
(1)使用char实例化出std::string
(2)提供了如find、substr等字符串特有的接口
(3)提供了数值与字符串转换的接口,to_string,stoi\stol等
(4)针对短字符串的优化,略
三.关联容器
关联容器,存在某种映射
3.1 索引
使用键进行索引
set/map/multiset/multimap
unordered_set / unordered_map / unordered_multiset / unordered_multimap
3.2 底层实现
set/map/multiset/multimap底层使用红黑树实现,有序方便搜索
unordered_xxx底层使用hash表实现,以便快速地查询是否元素已存在
3.3 set
底层用红黑树来实现,是一个二叉平衡搜索树
特性:
(1)从映射角度来理解,set中有某个元素时value为true、没有某个元素时value为false
(2)从有序角度来理解,set中的顺序是不重要的,但实际在存储时是有序的
功能:
(1)通常元素需要支持使用<比较大小,以便排序
(2)可以指定less或greater,或引入自定义的比较函数来比较大小关系
(3)插入元素,insert、emplace、emplace_hint(给出提示,提高插入速度)
(4)删除元素,erase
(5)访问元素,find、contains
(6)修改元素,extract返回节点对象,可以设置它的.value()
注意:set迭代器所指向的对象是const的,不能通过其修改元素
3.4 map
特性:
(1)树中每个节点是一个std::pair,->first为键,->second为value
(2)键需要支持使用<比较大小
(3)或者采用自定义的比较函数来引入大小关系
(4)访问元素:find、contains、[]、at,[]访问时如果没有key会自动创建
(5)删除元素:erase(key)
注意:
(1)map迭代器所指向的对象是std::pair,其键是const
(2)[]操作不能用于常量对象
3.5 multiset和multimap
与set和map类似,但允许重复键
元素访问:
(1)find返回首个查找到的元素
(2)count返回元素个数
(3)lower_bound/upper_bound/equal_range返回查找到的区间,lower和upper是找到的上下界,equal是起止迭代器
3.6 unordered_set/unordered_map/unordered_multiset/unordered_multimap
unordered,无序的
使用hash作键
特性:
(1)与set、map相比查找性能更好
(2)插入操作一些情况下会慢
(3)键需要支持两个操作,1是转换为hash值,2是判等
(4)除==和!=外,不支持容器级的关系运算,==和!=的运算较慢
(5)自定义hash与判等函数
四.适配器与生成器
4.1 类型适配器
basic_string_view
basic_string_view中的basic_string是一个字符容器,用于解决char*和string转换时的开销,统一起来方便使用
void fun(std::string_view str){
if(str.empty()) xxx;
}
可以直接传入char*或string
特性:
(1)可以基于std::string,C字符串,迭代器这三者进行构造
(2)构造成本很低,提供成本较低的操作接口
(3)只提供读,不可进行写操作
span
void fun(std::span<int> input){
input可以用for-range进行访问
}
int a[3]={1,2,3};
fun(a);
span是C++20引入的,提供对连续对象的封装
(1)可基于C数组、array等构造
(2)可读写
4.2 接口适配器
stack/queue/priority_queue
对底层序列容器进行封装,对外展现栈、队列与优先队列的接口
priority_queue在使用时其内部包含的元素需要支持比较操作
4.3 数值适配器
c++20引入,暂略
4.4 生成器
c++20引入,暂略
本文作者:OhOfCourse
本文链接:https://www.cnblogs.com/OhOfCourse/p/17173290.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步