STL中各类容器详细介绍

news2025/1/18 19:06:43

STL介绍

STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。

C++STL提供的数据结构

1. Sequence Containers:维持顺序的容器。

(a). vector:

动态数组,在堆中分配内存,是我们最常使用的数据结构之一。

特点:

  • 底层结构 : 底层由 动态数组 实现 , 特点是 存储空间 连续 ;
  • 访问遍历 : 支持 随机访问迭代器 , 可使用下标访问 , 访问元素非常快 O(1) 复杂度 ;
  • 插入 / 删除 : 尾部插入 / 删除效率高 O(1) 复杂度 ; 中间 和 头部插入/删除效率低 , 由于存储空间连续 , 需要将插入 / 删除位置之后的元素依次改变位置 , O(n) 复杂度 ;
  • 空间效率 : 底层实现时 , 会事先预留一些额外空间 , 以减少重新分配的次数 ;
  • 使用场景 : 需要 随机访问 且 频繁在尾部进行操作 的场景 ; 如果频繁增删元素 则 不适用该容器 ;

时间复杂度:

实现原理:

简单理解,就是vector是利用上述三个指针来表示的,基本示意图如下:
在这里插入图片描述
两个关键大小:
大小:size=_Mylast - _Myfirst;
容量:capacity=_Myend - _Myfirst;
分别对应于resize()、reserve()两个函数。


size表示vector中已有元素的个数,capacity表示vector最多可存储的元素的个数;

为了降低二次分配时的成本,vector实际配置的内存空间大小会比客户需求的更大一些,以备将来扩充,这就是capacity的概念。即capacity>=size,当等于时,容器此时已满,若再要加入新的元素时,就要重新进行内存分配,整个vector的数据都要移动到新内存。

vector:扩容机制:

vector 容器扩容的过程需要经历以下 3 步:

1. 完全弃用现有的内存空间,重新申请更大的内存空间;

2. 将旧内存空间中的数据,按原有顺序移动到新的内存空间中;

3. 最后将旧的内存空间释放。

因为 vector 扩容需要申请新的空间,所以扩容以后它的内存地址会发生改变。vector 扩容是非常耗时的,为了降低再次分配内存空间时的成本,每次扩容时 vector 都会申请比用户需求量更多的内存空间(这也就是 vector 容量的由来,即 capacity>=size),以便后期使用。VS里面扩容机制是1.5倍扩容,gcc里面是2倍扩容。


(b). list:

双向链表,也可以当作 stack 和 queue 来使用。有个缺点,链表不支持快速随机读取。

特点

  • 底层结构 : 底层由 双向链表 实现 , 特点是 存储空间 不连续 ;
  • 访问遍历 : 不支持 随机访问迭代器 , 只能通过迭代器进行访问 ;
  • 插入 / 删除 : 任意位置 插入 / 删除 效率都很高 ;
  • 空间效率 : 每个元素 都需要 分配额外的空间 , 存储 当前元素的 前驱元素 和 后继元素 ;
  • 使用场景 : 需要 在任意位置 频繁 插入 / 删除 操作的 场景 ;

时间复杂度:


(c). deque:

双端队列, 是一种优化了的、对序列两端元素进行添加和删除操作的基本序列容器。它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小。它不需要重新分配空间,所以在两端端增删元素比vector 更有效。

特点:

  • 底层结构 : 底层由 双向队列 实现 , 特点是 存储空间 连续 ;
  • 访问遍历 : 支持 随机访问迭代器 , 其性能比 vector 动态素组要低 ;
  • 插入 / 删除 : 头部 和 尾部 插入 / 删除效率高 , O(1) 复杂度 ; 中间 插入/删除效率低 , 由于存储空间连续 , 需要将插入 / 删除位置之后的元素依次改变位置 , 比 vector 动态数组要快一些 ;
  • 空间效率 : 底层实现时比 vector 的结构要复杂 , 也会事先预留一些额外空间 , 以减少重新分配的次数 ;
  • 使用场景 : 需要 随机访问 且 频繁在 首部 和 尾部 进行操作 的场景 ; 如果频繁 在中部 增删元素 则 不适用该容器 ;

实现原理:

deque 是由一段一段的定量的连续空间构成。一旦有必要在 deque 前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在 deque 的头端或者尾端。deque 最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口,避开了重新配置空间,复制,释放的轮回,代价就是复杂的迭代器架构。
既然 deque 是分段连续内存空间,那么就必须有中央控制,维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐。

deque 采取一块所谓的 map(不是 STL 的 map 容器)作为主控,这里所谓的 map 是一小块连续的内存空间,其中每一个元素(此处成为一个结点)都是一个指针,指向另一段连续性内存空间,称作缓冲区。缓冲区才是 deque的存储空间的主体。

时间复杂度:


(d). array:

固定大小的数组,一般在刷题时我们不使用。


(e). forward_list:

单向链表,一般在刷题时我们不使用。


2. Container Adaptors:容器适配器。

(a). stack:

后入先出(LIFO)的数据结构,默认基于 deque 实现。stack 常用于深度优先搜
索、一些字符串匹配问题以及单调栈问题。


(b). queue:

先入先出(FIFO)的数据结构,默认基于 deque 实现。queue 常用于广度优先
搜索。


(c). priority_queue:

最大值先出的数据结构,默认基于vector实现堆结构。它可以在O(n log n)
的时间排序数组,O(log n) 的时间插入任意值,O(1) 的时间获得最大值,O(log n) 的时
间删除最大值。priority_queue 常用于维护数据结构并快速获取最大或最小值。


3. Associative Containers:有序关联容器。

(a). set:

有序集合,元素不可重复,底层实现默认为红黑树,它可以在 O(n log n) 的时间排序数组,O(log n) 的时间插入、删除、查找任何节点。这里注意,set 和 priority_queue 都可以用
于维护数据结构并快速获取最大最小值,但是它们的时间复杂度和功能略有区别,如
priority_queue 默认不支持删除任意值,而 set 获得最大或最小值的时间复杂度略高,具
体使用哪个根据需求而定。

特点:

  • 底层结构 : 底层由 红黑树 实现 , 红黑树 是 一种 平衡二叉搜索树 , 存储空间 不连续 ;
  • 访问遍历 : 不支持 随机访问迭代器 , 不能通过过下标访问 , 只能通过迭代器进行访问 ;
  • 插入 / 删除 : 查询 / 插入 / 删除 效率 为 O(log n) 复杂度 ;
  • 排序方式 : 默认使用 less 仿函数 , 即 < 运算符进行排序 ; 也可以自定义 排序规则 仿函数 ;
  • 使用场景 : 需要 有序集合 且 元素 不重复 的场景 ;

时间复杂度:

增删改查都近似 = O(log N)


(b). multiset:

支持重复元素的 set。

(c). map:

有序映射或有序表,在 set 的基础上加上映射关系,可以对每个元素 key 存一个
值 value。

特点:

  • 底层结构 : 底层由 红黑树 实现 , 红黑树 是 一种 平衡二叉搜索树 , 存储空间 不连续 ; 存储的 元素 是 键值对 元素 ;
  • 访问遍历 : 不支持 随机访问迭代器 , 不能听过下标访问 , 只能通过迭代器进行访问 ;
  • 插入 / 删除 : 查询 / 插入 / 删除 效率 为 O(log n) 复杂度 ; 与 set 集合容器相同 ;
  • 排序方式 : 默认使用 less 仿函数 , 即 < 运算符进行排序 ; 也可以自定义 排序规则 仿函数 ; map 映射容器 不允许重复的键 , multimap 多重映射容器允许重复的键 ;
  • 使用场景 : 需要 有序 键值对 且 元素 不重复 的场景 ;
std::map 映射容器 与 std::set 集合容器 的区别是
map 容器存储的是 键值对 元素 , 元素是 pair  
set 容器 存储的是 单纯的 键 单个元素 ;

时间复杂度:

增删改查都近似 = O(log N)


(d). multimap:

支持重复元素的 map。


4. Unordered Associative Containers:无序关联容器

(a). unordered_set:

哈希集合,可以在 O(1) 的时间快速插入、查找、删除元素,常用于快
速的查询一个元素是否在这个容器内。


(b). unordered_multiset:

支持重复元素的 unordered_set。


(c). unordered_map:

哈希映射或哈希表,在 unordered_set 的基础上加上映射关系,可以对
每一个元素 key 存一个值 value。在某些情况下,如果 key 的范围已知且较小,我们也
可以用 vector 代替 unordered_map,用位置表示 key,用每个位置的值表示 value。

实现原理

unordered_map 容器和 map 容器一样,以键值对(pair类型)的形式存储数据,存储的各个键值对的键互不相同且不允许被修改。但由于 unordered_map 容器底层采用的是哈希表存储结构,该结构本身不具有对数据的排序功能,所以此容器内部不会自行对存储的键值对进行排序。底层采用哈希表实现无序容器时,会将所有数据存储到一整块连续的内存空间中,并且当数据存储位置发生冲突时,解决方法选用的是“链地址法”(又称“开链法”)。整个存储结构如下图(其中,Pi 表示存储的各个键值对):

可以看到,当使用无序容器存储键值对时,会先申请一整块连续的存储空间,但此空间并不用来直接存储键值对,而是存储各个链表的头指针,各键值对真正的存储位置是各个链表的节点。

为什么会出现哈希冲突:

由于通过哈希函数产生的哈希值是有限的,而数据可能比较多,导致经过哈希函数处理后仍然有不同的数据对应相同的值,这时候就产生了哈希冲突。

哈希冲突具体解决方法:

在正式讲解hash冲突之前,先介绍一个术语:在hashtable中,数组的每一个元素叫做桶(bucket)。

为了解决hash冲突,hashtable在每个桶里bucket[index]不再直接存储待插入节点的值,而是存储一个哨兵节点,使其指向一个链表,由这个链表来存储每次插入节点的值:

•桶的索引值index依然是bucket_index函数的计算方式,即通过待插入节点的键来获取•待插入节点的值在哨兵指向的链表头部插入,由于是头部插入整个插入过程还是O(1)时间复杂度。

当发生hash冲突时,将所有hashcode相同的节点都插入到同一个链表中,如图1所示。由于采用的是头部插入法,那么即便是发生了hash冲突,此时插入时间复杂度也依然是O(1)。

图片

图1  hash冲突的解决方法

上述解决hash冲突的方法,叫做开链法。此时,hash冲突的问题似乎解决了,能够插入多个hashcode一样的节点,并且插入操作的时间复杂度仍然是O(1)。

但是!!!,当出现严重的hash冲突,会造成bucket[idx]指向的链表节点很长,此时搜索和删除一个节点的时间复杂度最坏却可能变成O(N),即哈希表已经退化成链表,那么就违背了一开始设计hashtable的初衷,即弥补数组O(N)的搜索、删除时间复杂度。

 hash退化

 负载因子

为了解决hash退化,引入了两个概念:

•负载因子(load_factor),是hashtable的元素个数与hashtable的桶数之间比值;•最大负载因子(max_load_factor),是负载因子的上限

他们之间要满足:

load_factor = map.size() / map.buck_count() // load_factor 计算方式load_factor <= max_load_factor              // 限制条件

当hashtable中的元素个数与桶数比值load_factor >= max_load_factor时,hashtable就会自动增加桶数,并重新进行哈希扩容,并重新插入,来降低load_factor。

哈希扩容:即使分配一块更大内存,来容纳更多的桶。

重新插入:按照上述插入步骤将原来桶中的buck_size个节点重新插入到新的桶中。

Rehash后,桶数增加了而元素个数不变,再次满足load_factor <= max_load_factor条件。

 Rehash

hashtable,由于要一直满足 load_factor <= max_load_factor ,限制着hash冲突程度,即每个桶的链表节点数不会无限制增加,整个hashtable的节点数达到一定程度就会Rehash,确保hashtable的搜索、删除的平均时间复杂度还是O(1)。

在unordered_map有个rehash函数,可以在任意时候使unordered_map发生Rehash,也可以等load_factor > max_load_factor时自动发生。注意:

•不同编译器的扩容策略不同,因此不编译器Rehash后桶的个数不一致很正常。•目前msvc和g++中的max_load_factor字段默认值都是1。


(d). unordered_multimap:

支持重复元素的 unordered_map。

STL 各容器使用场景示例

  • 如果需要 随机访问 , 则使用 vector 单端数组 或 deque 双端数组 容器 ;
  • 如果 需要 在 尾部 频繁 插入 / 删除 , 则使用 vector 单端数组 ;
  • 如果 需要 在 首部 和 尾部 频繁 插入 / 删除 , 则使用 deque 双端数组 ;
  • 如果 需要 在 任意位置 频繁 插入 / 删除 , 则使用 list 双向链表 ;
  • 如果需要保持 元素 有序 且 不重复 , 则使用 set 集合容器 ;
  • 如果需要保持 元素 有序 且 可重复 , 则使用 multiset 多重集合容器 ;
  • 如果不需要保持 元素 有序 , 可使用unordered_set, unordered_map;


————————————————
引用:

https://blog.csdn.net/zuihaobizui/article/details/119741156

https://blog.csdn.net/shulianghan/article/details/135363350

https://www.cnblogs.com/yinbiao/p/11636405.html

C++ vector的内部实现原理及基本用法_vector内部实现-CSDN博客

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

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

相关文章

11-LINUX--信号

一.信号的基本概念 信号是系统响应某个条件而产生的事件&#xff0c;进程接收到信号会执行相应的操作。 与信号有关的系统调用在“signal.h”头文件中有声明 常见信号的值&#xff0c;及对应的功能说明&#xff1a; 信号的值在系统源码中的定义如下&#xff1a; 1. #define …

数学建模-最优包衣厚度终点判别法(主成分分析)

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是viperrrrrrr~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff…

STL容器(3)

1,stack容器 1.1 基本概念 概念&#xff1a;stack是一种先进后出的数据结构&#xff0c;它只有一个出口 因此&#xff1a; 栈中只有顶端的元素才可以被使用&#xff0c;因此占不允许有遍历行为 栈中进入数据称为--入栈&#xff08;push) 栈中弹出数据称为--出栈&#xff08…

SYS-2722音频分析仪SYS2722

181/2461/8938产品概述&#xff1a; Audio Precision 2722 音频分析仪是 Audio Precision 屡获殊荣的 PC 控制音频分析仪的旗舰型号&#xff0c;长期以来一直是音频设备设计和测试的全球公认标准。功能齐全的 SYS-2722 提供了测试转换器技术最新进展所需的无与伦比的失真和噪声…

[机缘参悟-164] :心理架构分层模型、马斯洛需求层次模型、冰山素质模型、恋爱背叛层次模型大一统架构

目录 一、大一统架构 1.1 需求层次模型讲的是什么&#xff1f;need、requirment 1.2 人的心理分层模型是什么 1.3 冰山模型讲的什么&#xff1f; 二、婚姻的本质 2.1 婚姻是在不同层面上建立关联 2.2 恋爱的本质 2.3 婚姻是在不同层面上满足对方的需求 一、大一统架构 …

Java NIO Selector选择器源码分析

文章目录 前言Selector类结构Selector抽象类AbstractSelectorSelectorImplWindowsSelectorImpl三种SelectionKey集合 前言 Java NIO&#xff08;New I/O&#xff09;的Selector选择器是一个用于多路复用&#xff08;Multiplexing&#xff09;的I/O操作的关键组件。它允许一个单…

css实现更改checkbox的样式;更改checkbox选中后的背景色;更改checkbox选中后的icon

<input class"check-input" type"checkbox"> .check-input {width: 16px;height: 16px;} /* 设置默认的checkbox样式 */input.check-input[type"checkbox"] {-webkit-appearance: none; /* 移除默认样式 */border: 1px solid #999;outl…

IAR激活The generation feature is not of version 18解决办法

参考文章&#xff1a; IAR9.30以上版本安装、注册、新建工程和配置过程详细介绍 IAR9.32资源&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1xxMLTe8yLSmjIrzDc4-DAQ?pwdled0 提取码&#xff1a;led0 注意事项&#xff1a; 需要把licpatcher64a.exe在每个文件夹…

【原创】springboot+vue校园座位预约管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

真--个人收款系统方案

此文主要说明方案&#xff0c;无代码部分 前言: 有个个人项目需要接入vip系统&#xff0c;我们发现微信、支付宝的官方API主要服务商户&#xff0c;而市面上的“个人收款系统”也往往不符合我们的需求。不过&#xff0c;每次支付时通知栏的信息给了我灵感。走投无路&#xff0…

回文链表 - LeetCode 热题 24

大家好&#xff01;我是曾续缘❣️ 今天是《LeetCode 热题 100》系列 发车第 24 天 链表第 3 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 回文链表 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &…

LeetCode - 移除石子使总数最小

1962. 移除石子使总数最小 当我看到这道题目的时候&#xff0c;第一时间想到的是&#xff1a;while循环 sort&#xff0c;时间复杂度 k*nlogn。题目要求执行k次操作后&#xff0c;剩下狮子的最小总数&#xff0c;我们是否可以考虑维护一个堆呢&#xff1f;堆顶值最大&#xff…

电商技术揭秘六:前端技术与用户体验优化

文章目录 引言一、前端技术在电商中的重要性1.1 前端技术概述1.2 用户体验与前端技术的关系 二、响应式设计与移动优化2.1 响应式设计的原则2.2 移动设备优化策略2.3 响应式设计的工具和框架 三、交互设计与用户体验提升3.1 交互设计的重要性3.2 用户体验的量化与优化3.3 通过前…

python笔记(9)Dictionary(字典)

目录 创建字典 取值 修改字典 删除 内置函数和方法 创建字典 字典键值和value用&#xff1a;隔开&#xff0c;键值是不可变的&#xff0c;而且必须是唯一的&#xff0c;值可以变&#xff0c;可以是任意类型 dict {key1 : value1, key2 : value2 } 1&#xff09;不允许同…

用友NC Cloud importhttpscer 任意文件上传漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,基于云原生架构,深度应用新一代数字技术,打造开放、 互联、融合、智能的一体化云平台,支持公有云、混合云、专属云…

c# wpf Template ContentTemplate

1.概要 1.1 定义内容的外观 2.2 要点分析 2.代码 <Window x:Class"WpfApp2.Window1"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schem…

使用 msys2 sshd为 windows 搭建 ssh 服务器

文章目录 概要整体架构流程技术名词解释MSYS2openSSH服务器 技术细节安装 MSYS2 环境安装openSSH配置、启动SSH 小结和扩展 概要 SSH服务器在Linux下的搭建一般的文章讨论的比较多了。在Windows下&#xff0c;我们常用Windows的Linux子系统来搭建ssh服务器。那有没有更好更简洁…

计算机网络—HTTP协议:深入解析与应用实践

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;ヒステリックナイトガール 1:03━━━━━━️&#x1f49f;──────── 5:06 &#x1f504; ◀️ ⏸ ▶️ ☰…

This app has no Android key hashes configured. . Configure your app key

Unity 接入 Facebook SDK 的过程中遇到这个问题&#xff0c;查了很多帖子&#xff0c;不太直观&#xff0c;记录下来方便需要的同学参考 报上面错误的原因是在https://developers.facebook.com/apps/ 设置里没有填入有效的密钥 怎么填入这个密钥呢&#xff0c;其实很简单&…

微电网优化:基于巨型犰狳优化算法(Giant Armadillo Optimization,GAO)的微电网优化(提供MATLAB代码)

一、微电网优化模型 微电网是一个相对独立的本地化电力单元&#xff0c;用户现场的分布式发电可以支持用电需求。为此&#xff0c;您的微电网将接入、监控、预测和控制您本地的分布式能源系统&#xff0c;同时强化供电系统的弹性&#xff0c;保障您的用电更经济。您可以在连接…