STL是C++的核心组成部分,其主要包括了容器迭代器算法三大组件。

其中容器负责存储数据,迭代器容器算法的桥梁,负责对容器中的元素进行操作。本文重点介绍容器部分内容。

STL主要容器

STL容器根据特性进行分类,可以分为序列式容器、关联容器、容器适配器

序列容器

序列容器重点在于根据元素的插入顺序而进行线性排列。

常见的序列容器有5种,分别是vector,list,deque,array,forward_list,这5种序列容器的底层实现原理和核心特性总结如下:

容器底层原理核心特性
vector拥有连续存储空间的动态数组,底层由3个指针,分别是:start,finish,end_of_stroage,通过这三个底层指针可以实现一些常规操作;具备动态扩容机制(一般为2倍)支持随机访问([]/at()),尾插和删除的复杂度为O(1),中间插入/头插/删除元素 O(n)
list底层数据结构是双向链表(内存空间不连续),每个节点都有数据,前驱指针和后继指针不支持随机访问,在任意位置插入/删除为 O(1),遍历元素效率O(n)
deque分段连续内存,有一个指针数组,存放每一段连续存储空间的地址支持双端高效插入/删除 O(1),随机访问效率略低于vector,整体来说集成了vectorlist的优点
array固定大小的静态数组,内存分配在大小不可变,随机访问高效,适合存储已知固定数量的元素
forward_list单向链表(仅包含后继指针)内存占用比list更小,仅支持单向遍历,插入/删除 O(1)

关联式容器

关联容器重点在于键值对的关联,元素根据按照键Key排序,元素的插入顺序不会影响到元素所处的位置,可以分为有序关联容器无序关联容器

有序关联容器

有序关联容器以为核心,元素会自动按照键的大小进行排序(默认情况下是升序排列std::less<key>,降序std::greater<int>)。这一类容器的底层数据结构是采用的红黑树(Red-Black Tree),红黑树是一种自平衡的二叉搜索树,红黑树的插入、删除、查找的时间复杂度都是**O(logn)**.

有序关联容器主要分为4种:setmapmultisetmultimap。它们的核心区别在于键是否唯一以及是否存储键值对.

1、set

存储唯一键的有序容器,其元素本身就是键(键=值),并且这里也不允许键重复,新插入的元素会按照键的大小自动排序,同时set种的元素是常量,不能直接修改(可能会破坏红黑树的性质),修改的正确操作过程应该是先删除旧元素,再插入新元素。由于红黑树的性质,在set插入或删除元素时,除被删除元素的迭代器外,其他迭代器均不会失效。

常见的接口操作:

  • insert(key)返回的是pair<iterator, bool>,标识是否插入成功
  • erase(key)/erase(iterator)删除匹配键的元素和迭代器指向的元素
  • find(key)查找某个key
  • count(key)计算某个key出现的次数
  • lower_bound(key)找到第一个不小于key(≥key)的迭代器,upper_bound(key)返回第一个大于key的元素迭代器

2、multiset

可以在set的基础上允许插入重复的键,元素按照键的大小有序排列。

常见的接口操作:

  • insert(key)返回新插入元素的迭代器
  • erase(key)删除所有匹配键的元素
  • count(key)计算某个key出现的次数
  • equal_range(key)返回是一个pair包含所有匹配键的元素范围[first, second),左闭右开区间

3、map

map 是存储键值对(key-value) 的有序容器,键(key)唯一,值(value)可修改。元素按键的大小自动排序,通过键可以快速访问对应的值。

底层基于红黑树,树的每个节点存储一个pair<const key, value>,所以键不可修改,值可以通过迭代器和[]修改

在插入时,不允许插入重复的键,insert会忽略重复键的插入;键一般用来查找和排序,值用来存储实际的元素,并且按照默认升序排列。

常见接口:

  • insert(pair<key, value>)(返回pair<iterator, bool>)、map[key] = value(若键存在则修改值,否则插入新键值对)。
  • erase(key)(删除键对应的键值对)、erase(iterator)
  • find(key)(返回指向键值对的迭代器)。
  • at(key)(安全访问,键不存在时抛异常)、map[key](非安全访问,键不存在时插入默认值)。
  • lower_boundupper_boundset一样

4、multimap

map的基础上允许插入重复的键,键值对按照键的大小有序排列。多个键值对可以有相同的键,按键有序排列(相同键的键值对相邻),由于键不唯一,所以不能使用[]操作符号,只能使用find或者equal_range

常见接口:

  • insert(pair<key, value>)总是成功,返回新元素迭代器
  • equal_range(key)返回包含所有相同键的键值对范围
  • erase(key)find(key)返回第一个匹配键的迭代器,与map类似

所以有序管理容器的总结如下:

容器底层原理核心特点
set红黑树,键值唯一,元素就是值元素自动按键升序排列,插入 / 删除 / 查找复杂度为 O (log n)
multiset红黑树,键可以重复插入特性同set,但支持键重复,插入 / 删除 / 查找仍为 O (log n)
map红黑树,存储键值对,键唯一按键升序排列,通过键快速访问值([]/at()),键不可重复
mutlimap红黑树,键值对,键可以重复,插入到相邻位置特性同map,但键可重复,不支持[]操作符(需用find()/equal_range()
无序关联容器

无序关联容器以键(key) 为核心的容器,其元素不按键的大小排序,而是通过哈希表(Hash Table)实现存储和访问。插入/删除/查找的平均时间复杂度为O(1)

底层的核心原理是哈希表(hashtable),重点包含以下三个部分:

  • 桶(Buckets):一个动态数组,每个元素(桶)是一个链表或红黑树的头指针,用于存储哈希值相同的元素(处理哈希冲突)
  • 哈希函数(Hash Function):将键(key)映射为桶的索引(整数),决定元素应该放入哪个桶
  • 相等比较器(Equality Comparator):判断两个键是否 “相等”(用于处理哈希冲突时,区分不同键但哈希值相同的元素)

在插入新元素时,通过哈希函数计算键的哈希值,得到桶的索引,将元素放入对应桶中;查找元素时,先通过哈希函数定位桶索引,然后在桶内遍历比较键,找到目标元素;当元素过多,超过负载因子时,触发重hash,分配更大的桶数组,重新计算哈希值,并且迁移到新的桶中。

1、unordered_set

存储唯一键的无序容器,元素本身就是键(“键 = 值”),键不允许重复,元素无序排列。适用于需要快速去重但是不需要关注元素顺序的场景

在插入重复键时,insert会被忽略,并且元素的顺序由哈希函数和插入顺序决定,于键的大小无关;由于键是常量,所有更新键的信息,需要删除旧元素插入新元素;插入时可能导致rehash导致所有迭代器失效,删除时只有被删除的元素的迭代器失效。

常见接口:

  • insert(key)返回pair<iterator, bool>bool表示是否插入成功
  • erase(key)删除所有匹配键的元素,返回删除数量、erase(iterator)
  • find(key)返回指向键的迭代器,不存在则返回end()
  • count(key)返回键的出现次数,只能是 0 或 1
  • bucket_count()当前桶数量、load_factor()当前负载因子、rehash(n)强制将桶数量设置为≥n

2、unordered_map

存储键值对(key-value) 的无序容器,键(key)唯一,值(value)可修改,元素无序排列,适用于需要通过唯一键快速查询值且不关心键顺序的场景,例如:缓存(键为 ID,值为缓存数据)、字典(无需按字母排序的键值映射)

插入重复键时,insert操作忽略,[]操作符会覆盖旧值;键用于哈希和查找,值存储实际数据,值可通过迭代器或[]修改;键值对顺序由哈希函数决定,与插入顺序和键大小无关。

常见接口:

  • insert(pair<key, value>)map[key] = value键不存在则插入,存在则修改值
  • at(key)安全访问,键不存在抛异常、map[key]不安全访问,键不存在插入默认值
  • find(key)erase(key)等与unordered_set类似

3、unordered_multiset

unordered_set的 “多重” 版本,允许存储重复的键(键可以不唯一),元素无序排列(相同键的元素相邻),适用于需要存储重复元素不关心顺序的场景,例如:统计元素出现频率(如词频统计)、存储多个相同优先级的任务

4、unordered_multimap

unordered_map的 “多重” 版本,允许存储重复的键(键值对的键可以不唯一),元素无序排列(相同键的键值对相邻),多个键值对可拥有相同的键,相同键的键值对在同一桶中相邻,适用于需要通过重复键映射多个值不关心顺序的场景。

无序关联容器总结:

容器底层原理核心特性
unordered_set哈希表(数组 + 链表 / 红黑树),键唯一元素无序,插入 / 删除 / 查找平均复杂度 O (1)(最坏 O (n),取决于哈希冲突),键唯一。
unordered_map哈希表,存储键值对,键唯一无序,通过键快速访问值,平均 O (1) 操作,键唯一
unordered_multiset哈希表,键可重复无序,支持键重复,平均 O (1) 操作
unordered_multimap哈希表,键值对,键可重复无序,键可重复,平均O (1) 操作

容器适配器

容器适配器是一类特殊的容器,它们不直接实现数据存储,而是通过封装底层容器(如vectordequelist等)来提供特定的接口和功能。核心作用是:限制对底层容器的访问方式,只暴露符合特定数据结构逻辑的操作

主要特点:

  • 本身不存储数据,数据实际上存储在底层容器中,适配器仅仅提供上层的接口
  • 屏蔽底层容器的大部分操作,只保留符合自身发展逻辑的接口(stack仅允许栈顶操作)
  • 适配器没有迭代器,不支持遍历或者随机访问
  • 默认使用特定的容器作为底层实现(如stack使用deque),但是也可以通过模板参数指定其他符合要求的容器
主要的容器适配器类型
1、stack

stack遵循后进先出规则,仅仅允许在栈顶进行操作,插入、删除和访问等。

其底层的容器为deque,主要原因是:

  • deque的尾部插入和删除的效率都是O(1)
  • deque可以减少频繁扩容导致的内存重分配
  • list相比,deque的内存连续性更好,缓存利用率更高

核心操作有:

  • push(val):在栈顶插入元素(调用底层容器的push_back)。
  • pop():删除栈顶元素(调用底层容器的pop_back不返回元素)。
  • top():返回栈顶元素的引用(调用底层容器的back)。
  • empty():判断栈是否为空。
  • size():返回元素个数。

实现

template <typename T, typename Sequence = std::deque<T>> 
class stack {
public:using value_type = typename Sequence::value_type;using size_type = typename Sequence::size_type;using reference = typename Sequence::reference;using const_reference = typename Sequence::const_reference;using container_type = Sequence;// 各类接口bool empty() const {return container_.empty();}size_type size() const {return container_.size();}const_reference top() const {return container_.back();}void push(const value_type &v)  {container_.push_back(v);}void pop() {container_.pop_back();}template<typename... Args>void emplace(Args&& ...args) {container_.emplace_back(std::forward<Args>(args)...);}void swap(stack& other) {container_.swap(other.container_);}private:// 唯一的成员变量就是底层的容器containter_type container_;
}
2、queue

queuq遵循FIFO规则,允许在队尾插入,队头删除和访问。

底层的默认容器还是deque,主要原因是:

  • deque支持队尾插入(push_back)和队头删除(pop_front),两者效率均为 O (1)
  • 若用vector作为底层,pop_front操作需移动所有元素(O (n),效率低)
  • list虽支持 O (1) 的头尾操作,但内存连续性差,缓存命中率低

核心操作有:

  • push(val):在队尾插入元素(调用push_back)。
  • pop():删除队头元素(调用pop_front不返回元素)。
  • front():返回队头元素的引用(调用front)。
  • back():返回队尾元素的引用(调用back)。
  • empty()/size():判断空或返回元素个数。

实现

template <typename T, typename Sequence = std::deque<T>>
class queue {
public:using value_type = typename Sequence::value_type;using size_type = typename Sequence::size_type;using reference = typename Sequence::reference;using const_reference = typename Sequence::const_reference;using container_type = Sequence;bool empty() const {return container_.empty();}size_type size() const {return container_.size();}reference front() const {return container_.front();}const_reference front() const {return container_.front();}reference_back() {return container_.back();}const_reference back() const {return container_.back();}void push(value_type& v) {container_.push_back(v);}void pop() {container_.pop_front();}template<typename ...Args>void emplace_back(Args&& ...args) {container_.emplace_back(std::forward<Args>(args)...);}void swap(queue& other) {container_.swap(other.container_);}private:container_type container_;
}
3、priority_que

priority_que是优先级队列,也是一种适配器,每次删除的其中的优先级最高的元素(默认最大元素),插入时会自动调整元素的位置以维持优先级顺序。

priority_que底层使用的容器是vector,主要原因是:

  • priority_que逻辑是一个二叉堆,需要随机访问定位父子节点的位置(如父节点的下标为i,那么其左孩子的下标为2*i + 1,右孩子的下标为2*i + 2)
  • vector随机访问的效率最好,内存连续,具有局部性原理,并且堆的上浮和下沉操作效率更高

它默认使用std::less<T>作为比较器(大顶堆),std::greater<T>为小顶堆

priority_queue<int, vector<int>, std::greater<int>> min_heap

核心操作有

  • push(val):插入元素并调整堆结构(确保优先级最高的元素在顶部,复杂度 O (log n))。
  • pop():删除顶部(优先级最高)的元素并调整堆(复杂度 O (log n),不返回元素)。
  • top():返回顶部元素的引用(调用底层容器的front)。
  • empty()/size():判断空或返回元素个数。

实现

template<typename T, typename Container = std::vector<int>,typename Comp = std::less<typename Container::value_type>>class priority_queue {public:using value_type = T;using size_type = typename Container::size_type;/// 构造函数explicit priority_queue(const Container& container = Container(), const Comp& comp = Comp())  : comp_(comp), container_(container){/// 利用容器的头尾迭代器构造一个堆std::make_heap(container_.begin(), container_.end(), comp_);}// 拷贝构造和移动构造,赋值,移动赋值都是默认priority_queue(priority_queue &&) noexcept = default;priority_queue &operator=(priority_queue &&) noexcept= default;priority_queue(const priority_queue &) = default;priority_queue &operator=(const priority_queue &) = default;/// 输入迭代器版本的构造函数template<typename InputIterator>priority_queue(InputIterator first, InputIterator last, const Comp& comp = Comp(), const Container& container = Container()) : container_(container), comp_(comp) {std::make_heap(container_.begin(), container_.end(), comp_);}// 下面是常见的接口bool empty() const {return container_.empty();}size_type size() const {return container_.size();}const value_type& top() const {return container_.front();}value_type& top() {return container_.front();}void push(const valye_type& value) {container_.push_back(value);std::push_heap(container_begin(), container_.end(), comp_);}void push(valye_type&& value) {container_.push_back(std::move(value));std::push_heap(container_begin(), container_.end(), comp_);}void pop() {std::pop_heap(container_.begin(), container_end(), comp_);container_.pop_back();}void swap(priority_que& other) {std::swap(comp_, other.comp_);std:;swap(container_, other.container_);}template<typename ...Args>void emplace_back(Args&& ...args) {container_.emplace_back(std::forward<Args>(args)...);std::push_heap(container_.begin(), container_.end(), comp_);}private:// 成员变量主要有比较器和容器Container container_;Comp comp_;}

最后,如有错误,请各位大佬海涵,我一定努力改正,如有侵权,请联系我删除~

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

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

相关文章

微信小程序 拖拽签章

微信小程序 拖拽签章 效果 主要实现的功能点 文件按比例加载图片(宽高设定拖拽范围) 弹层展示印章模板 模板拖拽到文件图片上 实时获取拽拽位置 难点 弹层中的元素如何拖拽到文件图片上 实现历程 版本1.0 以前我们拖拽一个图层到另一个图层上,pc端使用的是mousedown mou…

人工智能加速计算套件

按照甲方要求的技术指标的人工智能加速计算套件1套。每套包含以下内容&#xff1a; 1、显卡 不低于6542Y&#xff1b;容量不低于 48GB GDDR6显存&#xff1b;CUDA核心不低于14080 个 &#xff1b;第四代Tensor Core不低于440 个&#xff1b;单精度性能不低于69.3 TFLOPS&#x…

端到端测试:复杂系统的终极体检术

当你的应用像多米诺骨牌一样牵一发而动全身&#xff0c;如何确保用户一路畅通无阻&#xff1f;一、为什么我们需要端到端测试&#xff1f; 想象一下&#xff1a;你精心开发的电商应用&#xff0c;用户登录顺利&#xff0c;商品浏览流畅&#xff0c;却在最后支付时卡壳——原因是…

Perf使用详解

Perf 工具深度解析 Perf&#xff08;Performance Counters for Linux&#xff09;是 Linux 系统的性能分析工具&#xff0c;基于内核的 perf_event 子系统&#xff0c;通过硬件性能计数器&#xff08;PMC&#xff09;、软件事件和跟踪点&#xff08;tracepoints&#xff09;实现…

Windchill 11 Enumerated Type Customization Utility-枚举类型自定义实用程序

一、Enumerated Type Customization Utility 枚举类型自定义实用程序&#xff0c;可用于添加或编辑枚举类型的值&#xff0c;在Windchill 12.0中可直接在类型和属性管理中编辑&#xff0c;如下图所示&#xff0c;而在Windchill 11.0中只能通过windchill shell启动程序&#xff…

git疑问,暂时记录

有时候把dev本地分支搞乱了,多出几个提交,好像在远程仓库,rebase dev到本地dev,就恢复了,然后再把我开发分支合并过去就ok,就不会多出几个重复的提交 在自己分支开发提交数据后,不push到远程仓库 然后合并到dev分支,推dev分支到远程仓库然后在自己分支,rebase到自己分支,然后再…

Java 大视界 -- 基于 Java 的大数据分布式计算在气象灾害预警与应急响应中的应用

Java 大视界 -- 基于 Java 的大数据分布式计算在气象灾害预警与应急响应中的应用引言&#xff1a;Java 筑起气象防灾减灾的数字长城正文&#xff1a;Java 构建的气象智慧防御体系一、气象大数据的 Java 基座&#xff1a;从采集到存储的全链路优化1.1 多源异构数据的实时汇聚1.2…

MySQL黑盒子研究工具 strace

strace是什么&#xff1f; 按照 strace 官网的描述, strace 是一个可用于诊断、调试和教学的 Linux 用户空间跟踪器。我们用它来监控用户空间进程和内核的交互&#xff0c;比如系统调用、信号传递、进程状态变更等。 strace 底层使用内核的 ptrace 特性来实现其功能。 strace能…

【运维进阶】实施任务控制

实施任务控制 在 Ansible 中&#xff0c;“实施任务控制” 通常指的是对任务执行流程的控制&#xff0c;比如&#xff1a; 条件执行&#xff08;when&#xff09; 循环执行&#xff08;with_items / loop&#xff09; 错误处理&#xff08;block / rescue / ignore_errors&…

Java 中的线程中断详解

Java 中的线程中断1、什么是线程中断2、如何触发线程中断3、如何处理线程中断3.1 线程中断相关的核心方法3.2 处理中断的典型方式3.3 注意事项4、线程中断与线程终止的区别5、线程中断的应用场景5.1 长时间运行任务的取消5.2 阻塞操作的快速响应5.3 服务或线程池的优雅关闭5.4 …

【LeetCode题解】LeetCode 33. 搜索旋转排序数组

【题目链接】 33. 搜索旋转排序数组 【题目描述】 【题解】 对于一个有序数组&#xff0c;我们可以使用二分查找算法来查找某个元素&#xff0c;具体的算法模板可以参考【算法基础课-算法模板1】基础算法中二分查找一节的内容。 然而&#xff0c;在这道题目中&#xff0c;数组…

使用 Serverless 架构快速构建基于 Iceberg 的事务型实时数据湖

文章目录1. 背景介绍2. 架构设计3. 方案实现3.1 CDC3.1.1 自定义插件3.1.2 配置 MSK Connect3.2 实时摄入3.2.1 Glue 实现方案3.2.1.1 在 Glue 中创建 Kafka connection3.2.1.2 Glue Streaming 任务3.2.2 EMS Serverless 实现方案3.3 使用 Athena 查询 Iceberg 表3.3.1 查询3.3…

Java零基础笔记20(Java高级技术:单元测试、反射、注解、动态代理)

1.单元测试2.反射2.1 反射第一步&#xff1a;加载类&#xff0c;获取类的字节码&#xff0c;class对象2.2 获取类中的成分&#xff08;构造器、成员变量、成员方法&#xff09;&#xff0c;并对其进行操作获取构造器的作用&#xff1a;获取成员变量的作用&#xff1a;获取成员…

WinDbg 调试

安装 Windows 调试器 WinDbg 是一种调试器,可用于分析故障转储、调试实时用户模式和内核模式代码,以及检查 CPU 寄存器和内存。 此最新版本具有更新的界面、完全现成的脚本功能、可扩展的调试数据模型、内置的时间旅行调试(TTD)支持和许多其他功能,具有更现代的用户体验。…

topographic terrain

在中文语境中&#xff0c;topographic&#xff08;地形学&#xff09;和 terrain&#xff08;地形&#xff09;这两个词都与地表特征相关&#xff0c;但它们的含义和使用场景有细微差别。以下是它们的区别&#xff1a; 1. 定义Topographic&#xff08;地形学的&#xff09;&…

SpringCloud 06 服务容错 Sentinel

雪崩&#xff1a;一个微小的故障引起系统其他部分出现故障&#xff0c;最终使整个系统不可用。 雪崩一般经历以下三个阶段&#xff1a; 实例能力出现过载。可能是 bug 导致性能下降&#xff0c;可能是实例宕机&#xff0c;可能是突发流量&#xff0c;总之实例无法处理如此多请求…

Qt同步处理业务并禁用按钮

1.界面代码 //按钮1 void Dialog::on_pushButton1_clicked() {qDebug("pushButton1 clicked start");enableBtns(false);//禁用按钮qDebug("pushButton1 do sth start");QThread::sleep(5);//休眠&#xff0c;作为同步处理业务qDebug("pushButton1 do…

虚拟专用网技术

一、需求背景物理联通&#xff1a;实现不同物理位置网络的连接基础。网络联通&#xff1a;在物理连接基础上&#xff0c;实现数据等信息的传输互通。二、虚拟专用网简介定义虚拟私有网络是依靠互联网服务提供商&#xff08;ISP&#xff09;或其他网络服务提供商&#xff08;NSP…

GANs生成对抗网络生成手写数字的Pytorch实现

目录 一、第三方库导入 二、数据集准备 三、使用转置卷积的生成器 四、使用卷积的判别器 五、生成器生成图像 六、主程序 七、运行结果 7.1 生成器和判别器的损失函数图像 7.2 训练过程中生成器生成的图像 八、完整的pytorch代码 由于之前写gans的代码时&#xff0c;…

ubuntu 通过NAT模式上网

这里必须使用VMnet8 设置为NAT模式 下面设置Ip地址区域ubuntu ip地址设置来自于上面