当前位置: 首页 > news >正文

C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程

引言

C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(std::vectorstd::arraystd::liststd::deque)、关联容器(std::setstd::map)和无序容器(std::unordered_setstd::unordered_map),全面解析它们的特点、用法、适用场景及常见操作。


一、C++ 容器的分类

C++ 容器按照用途大致分为三大类:

  1. 序列容器(Sequence Containers)

    • 元素按顺序存储。
    • 支持动态调整大小和顺序访问操作。
    • 包括:std::vectorstd::arraystd::dequestd::list
  2. 关联容器(Associative Containers)

    • 元素以键值对存储,通常用于高效查找。
    • 数据存储有序,底层实现为平衡二叉树(如红黑树)。
    • 包括:std::setstd::mapstd::multisetstd::multimap
  3. 无序容器(Unordered Containers)

    • 元素以哈希表存储,查找性能优于关联容器,但数据无序。
    • 包括:std::unordered_setstd::unordered_map

二、序列容器解析

序列容器的特点是元素按插入顺序排列,适用于处理需要频繁访问或者保持顺序的数据场景。

1. std::vector

简介

std::vector 是一个动态数组,支持自动扩展和随机访问,适用于需要频繁随机访问的场景。它是初学者最常使用的容器之一,因为它的使用方式和普通数组非常类似,但多了动态管理内存的功能。

特点
  • 动态扩展std::vector 的大小会根据需求动态调整,当元素数目超过当前容量时,它会自动分配更多的内存来容纳新元素。
  • 连续存储:数据存储在连续的内存块中,因此访问性能高,遍历时效率优于链表等非连续存储容器。
  • 插入和删除效率
    • 尾部操作高效:在尾部添加或删除元素的时间复杂度是 (O(1)),非常高效。
    • 中间插入或删除效率低:由于 vector 是连续存储,插入或删除中间元素时,需移动大量元素,因此效率为 (O(n))。
常用操作
操作方法描述
添加元素push_back()在尾部插入元素
删除尾部元素pop_back()删除尾部元素
插入元素insert(iterator, value)在指定位置插入元素
删除指定元素erase(iterator)删除指定位置的元素
随机访问元素operator[]at()随机访问指定索引处的元素
获取大小size()返回当前元素数量
检查是否为空empty()判断容器是否为空
示例代码
#include <vector>
#include <iostream>int main() {std::vector<int> vec = {1, 2, 3};// 添加元素vec.push_back(4);  // 在尾部添加元素 4// 修改元素vec[1] = 20;  // 修改第二个元素的值为 20// 插入和删除vec.insert(vec.begin() + 2, 10); // 在索引 2 的位置插入元素 10vec.erase(vec.begin() + 1);      // 删除索引 1 的元素// 遍历并输出元素for (int val : vec) {std::cout << val << " ";} // 输出 1 10 3 4return 0;
}

适用场景

std::vector 适合需要频繁随机访问或尾部增删元素的场景,比如处理一组动态变化的数值或管理待办事项列表等。


2. std::array

简介

std::array 是固定大小的静态数组,大小在编译时确定。它的用法与普通 C 风格数组非常相似,但提供了一些更安全、更便捷的操作接口。

特点
  • 轻量高效std::array 是静态分配的,因此不涉及动态内存分配,这使得它非常高效。
  • 固定大小:数组大小在编译时确定,因此不支持动态扩展,适合已知大小的数据集合。
  • 随机访问高效:访问任意元素的时间复杂度为 (O(1)),类似普通数组。
常用操作
操作方法描述
访问元素operator[]at()随机访问元素
获取大小size()返回固定大小
获取头尾元素front() / back()获取第一个或最后一个元素
填充所有元素fill(value)用指定值填充整个数组
示例代码
#include <array>
#include <iostream>int main() {std::array<int, 4> arr = {1, 2, 3, 4};arr[2] = 10;  // 修改第三个元素的值为 10// 遍历并输出元素for (int val : arr) {std::cout << val << " ";} // 输出 1 2 10 4return 0;
}

适用场景

std::array 适合用于需要固定大小且已知的数据集合,比如存储 RGB 颜色值或者某个固定大小的矩阵行数据。


3. std::list

简介

std::list 是双向链表,适用于频繁的中间插入和删除操作。在链表中,每个元素都有一个指向前后元素的指针,这使得在任何位置进行插入和删除都非常高效。

特点
  • 高效插入和删除:在链表中的插入和删除时间复杂度为 (O(1)),不需要像 vector 一样移动其他元素。
  • 随机访问效率低:由于链表没有连续存储,不能通过索引直接访问某个元素,必须从头或尾遍历,因此随机访问的效率很低。
常用操作
操作方法描述
添加元素push_front() / push_back()在头部或尾部添加元素
删除元素pop_front() / pop_back()删除头部或尾部元素
插入元素insert(iterator, value)在指定位置插入元素
删除指定元素erase(iterator)删除指定位置的元素
示例代码
#include <list>
#include <iostream>int main() {std::list<int> lst = {1, 2, 3};lst.push_back(4);  // 在尾部添加元素 4lst.insert(std::next(lst.begin(), 1), 10);  // 在第二个位置插入元素 10lst.pop_front();                            // 删除头部元素// 遍历并输出元素for (int val : lst) {std::cout << val << " ";} // 输出 10 2 3 4return 0;
}

适用场景

std::list 适合频繁的中间插入和删除,尤其是当数据集合较大并且需要灵活调整时,比如管理网络节点或实现复杂的缓存算法。


4. std::deque

简介

std::deque 是双端队列,支持在头部和尾部快速插入和删除。它可以理解为 vectorlist 的结合,具有两者的优点。

特点
  • 高效双端操作:无论是头部还是尾部插入/删除,时间复杂度均为 (O(1))。
  • 支持随机访问:与 vector 类似,deque 支持通过索引直接访问元素,但它的底层存储结构并非一个连续的内存块。
常用操作
操作方法描述
添加元素push_front() / push_back()在头部或尾部添加元素
删除元素pop_front() / pop_back()删除头部或尾部元素
随机访问元素operator[]at()随机访问元素
示例代码
#include <deque>
#include <iostream>int main() {std::deque<int> dq = {1, 2, 3};dq.push_front(0);  // 在头部添加元素 0dq.push_back(4);   // 在尾部添加元素 4// 遍历并输出元素for (int val : dq) {std::cout << val << " ";} // 输出 0 1 2 3 4return 0;
}

适用场景

std::deque 适合在头尾都需要频繁增删数据的场景,比如模拟队列或双向缓存。


三、关联容器解析

关联容器用于存储键值对,通常用于高效查找、插入和删除操作。

1. std::set

简介

std::set 是集合容器,用于存储不重复的元素,底层实现为红黑树,具有自动排序的功能。

特点
  • 有序存储:元素按照升序排列,保证数据有序。
  • 查找高效set 使用平衡二叉树,查找、插入和删除的时间复杂度为 (O(\log n))。
  • 唯一性set 保证集合中不会有重复的元素。
常用操作
操作方法描述
添加元素insert(value)插入一个元素
删除元素erase(iterator)删除指定元素
查找元素find(value)查找元素是否存在
示例代码
#include <set>
#include <iostream>int main() {std::set<int> s = {3, 1, 4};s.insert(2);  // 插入元素 2s.erase(1);   // 删除元素 1// 遍历并输出元素for (int val : s) {std::cout << val << " ";} // 输出 2 3 4return 0;
}

适用场景

std::set 适合需要保证数据唯一性并且需要有序存储的场景,比如保存用户 ID、追踪唯一的值等。


2. std::map

简介

std::map 是键值对容器,类似于字典,它也是通过红黑树实现的,因此提供了有序的数据存储方式。

特点
  • 有序存储:键值对按照键的顺序存储。
  • 查找高效map 的查找、插入和删除操作的时间复杂度为 (O(\log n))。
  • 键唯一:每个键都是唯一的。
常用操作
操作方法描述
添加元素operator[]insert()添加或更新键值对
删除元素erase(iterator)删除指定键的元素
查找元素find(key)查找指定键是否存在
示例代码
#include <map>
#include <iostream>int main() {std::map<int, std::string> m = {{1, "one"}, {2, "two"}};m[3] = "three";  // 插入键值对 (3, "three")// 遍历并输出键值对for (auto& [key, value] : m) {std::cout << key << ": " << value << std::endl;}return 0;
}

适用场景

std::map 适合需要快速查找键值对的场景,比如存储用户信息或用于配置文件读取等。


总结:容器的选择指南

场景推荐容器
随机访问std::vector
数据大小固定且已知std::array
频繁插入和删除std::liststd::deque
有序存储和查找std::setstd::map
无序存储和查找std::unordered_set / std::unordered_map

通过掌握这些容器的特性和用法,你将能够在开发中游刃有余地选择最佳的容器,为程序带来性能和代码可读性的提升。对于刚开始学习 C++ 的萌新们,理解这些容器的基本特性和适用场景,是提高编程技能的重要一步!希望这篇文章对你理解和使用 C++ 容器有所帮助。
在这里插入图片描述

相关文章:

C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程

引言 C 标准模板库&#xff08;STL&#xff09;提供了一组功能强大的容器类&#xff0c;用于存储和操作数据集合。不同的容器具有独特的特性和应用场景&#xff0c;因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C 的开发者来说&#xff0c;了解这些容…...

C++---类型转换

文章目录 C的类型转换C的4种强制类型转换RTTI C的类型转换 类型转换 内置类型之间的转换 // a、内置类型之间 // 1、隐式类型转换 整形之间/整形和浮点数之间 // 2、显示类型的转换 指针和整形、指针之间 int main() {int i 1;// 隐式类型转换double d i;printf("%d…...

CSS基础学习练习题

编程题 1.为下面这段文字定义字体样式&#xff0c;要求字体类型指定多种、大小为14px、粗细为粗体、颜色为蓝色。 “有规划的人生叫蓝图&#xff0c;没规划的人生叫拼图。​” 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><me…...

TypeScript知识点总结和案例使用

TypeScript 是一种由微软开发的开源编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;提供了静态类型检查和其他一些增强功能。以下是一些 TypeScript 的重要知识点总结&#xff1a; 1. 基本类型 TypeScript 支持多种基本数据类型&#xff0c;包括&#xff1a; numbe…...

解决BUG: Since 17.0, the “attrs“ and “states“ attributes are no longer used.

从Odoo 17.0开始&#xff0c;attrs和states属性不再使用&#xff0c;取而代之的是使用depends和domain属性来控制字段的可见性和其他行为。如果您想要在选择国家之后继续选择州&#xff0c;并且希望在选择了国家之后才显示州字段&#xff0c;您可以使用depends属性来实现这一点…...

单片机GPIO中断+定时器 实现模拟串口接收

单片机GPIO中断定时器 实现模拟串口接收 解决思路代码示例 解决思路 串口波特率9600bps,每个bit约为1000000us/9600104.16us&#xff1b; 定时器第一次定时时间设为52us即半个bit的时间&#xff0c;其目的是偏移半个bit时间&#xff0c;之后的每104us采样并读取1bit数据。使得…...

《深入理解 Spring MVC 工作流程》

一、Spring MVC 架构概述 Spring MVC 是一个基于 Java 的轻量级 Web 应用框架&#xff0c;它遵循了经典的 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;将请求、响应和业务逻辑分离&#xff0c;从而构建出灵活可维护的 Web 应用程序。 在 Spring MV…...

HTML简介

知识点一 HTML 什么是HTML&#xff1f; 超文本标记语言(HyperTextMarkup Language&#xff0c;简称HTML) 怎么学HTML&#xff1f; HTML 是一门标记语言&#xff0c;标记语言由一套标记标签组成&#xff0c;学习 HTML&#xff0c;其实就是学习标签 开发工具 编辑器: Pycha…...

Linux系统Centos设置开机默认root用户

目录 一. 教程 二. 部分第三方工具配置也无效 一. 教程 使用 Linux 安装Centos系统的小伙伴大概都知道&#xff0c;我们进入系统后&#xff0c;通常都是自己设置的普通用户身份&#xff0c;而不是 root 超级管理员用户&#xff0c;导致我们在操作文件夹时往往爆出没有权限&am…...

【网络安全 | 甲方建设】双/多因素认证、TOTP原理及实现

未经许可,不得转载。 文章目录 背景双因素、多因素认证双因素认证(2FA)多因素认证(MFA)TOTP实现TOTP生成流程TOTP算法TOTP代码示例(JS)Google Authenticator总结背景 在传统的在线银行系统中,用户通常只需输入用户名和密码就可以访问自己的账户。然而,如果密码不慎泄…...

Nuxt3 动态路由URL不更改的前提下参数更新,NuxtLink不刷新不跳转,生命周期无响应解决方案

Nuxt3 动态路由URL不更改的前提下参数更新&#xff0c;NuxtLink不刷新不跳转&#xff0c;生命周期无响应解决方案 首先说明一点&#xff0c;Nuxt3 的动态路由响应机制是根据 URL 是否更改&#xff0c;参数的更改并不会触发 Router 去更新页面&#xff0c;这在 Vue3 上同样存在…...

2024华为java面经

华为2024年Java招聘面试题目可能会涵盖Java基础知识、核心技术、框架与工具、项目经验以及算法与数据结构等多个方面。以下是考的内容。 一、Java基础知识 Java中有哪些基本数据类型&#xff1f; Java为什么能够跨平台运行&#xff1f; String是基本数据类型吗&#xff1f;能…...

2021 年 9 月青少年软编等考 C 语言三级真题解析

目录 T1. 课程冲突思路分析T2. 余数相同问题思路分析T3. 生成括号思路分析T4. 广义格雷码思路分析T5. 菲波那契数列思路分析T1. 课程冲突 小 A 修了 n n n 门课程,第 i i i 门课程是从第 a i a_i ai​ 天一直上到第 b i b_i bi​ 天。 定义两门课程的冲突程度为:有几天…...

深度解析FastDFS:构建高效分布式文件存储的实战指南(下)

接上篇&#xff1a;《深度解析FastDFS&#xff1a;构建高效分布式文件存储的实战指南&#xff08;上&#xff09;》 传送门: link 文章目录 六、常用命令七、FastDFS配置详解7.1 tracker配置文件7.2 tracker目录及文件结构7.3 storage配置文件7.4 storage服务器的目录结构和文件…...

Python学习29天

二分查找 # 定义函数冒泡排序法从大到小排列 def bbble_sort(list):# i控制排序次数for i in range(len(list) - 1):# j控制每次排序比较次数for j in range(len(list) - 1 - i):if list[j] < list[j 1]:list[j], list[j 1] list[j 1], list[j] # 定义二分查找函数 def…...

Soul App创始人张璐团队携多模态大模型参加GITEX GLOBAL,展现未来社交趋势

作为中东地区规模最大、最成功的计算机通讯及消费性电子产品展,GITEX GLOBAL一直颇受全球关注,于今年迎来了第44届盛会。自诞生以来,GITEX GLOBAL始终聚焦技术驱动的创新,吸引了许多科技巨头、创新企业及投资者的参与。Soul App作为中国较早将AI技术引入社交的企业,今年首次亮相…...

简单工厂模式、方法工厂模式

简单工厂模式&#xff08;Simple Factory Pattern&#xff09; 简单工厂模式的核心思想是通过一个工厂类&#xff0c;根据提供的参数来决定创建哪一个具体的产品类实例。 这个模式通常用于产品种类较少&#xff0c;且不经常变化的场景。 interface Product {void create(); }…...

【面试】前端vue项目架构详细描述

基于您提供的技术栈和要求&#xff0c;以下是前端项目的架构设计描述&#xff1a; 项目结构 • 入口文件&#xff1a; main.js 作为项目的入口文件&#xff0c;负责初始化 Vue 实例&#xff0c;并挂载到 DOM 上。 • 组件目录&#xff1a; components 目录包含项目的所有 Vue 组…...

BERT的中文问答系统32

我们需要在现有的代码基础上增加网络搜索功能&#xff0c;并在大模型无法提供满意答案时调用网络搜索。以下是完整的代码和文件结构说明&#xff0c;我们创建一个完整的项目结构&#xff0c;包括多个文件和目录。这个项目将包含以下部分&#xff1a; 主文件 (main.py)&#xf…...

大数据-226 离线数仓 - Flume 优化配置 自定义拦截器 拦截原理 拦截器实现 Java

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…...

idea maven 重新构建索引

当设置maven仓库为离线模式的时候&#xff0c;会出现一些问题。 比如本地的仓库被各种方式手动更新之后&#xff0c; 举例&#xff1a;我需要一个spring的包&#xff0c;在pmo文件中写好了引入包的代码 但是由于是离线模式没有办法触发自动下载&#xff0c;那么这个时候我可以…...

C#桌面应用制作计算器

C#桌面应用制作简易计算器&#xff0c;可实现数字之间的加减乘除、AC按键清屏、Del按键清除末尾数字、/-按键取数字相反数、%按键使数字缩小100倍、按键显示运算结果等...... 页面实现效果 功能实现 布局 计算器主体使用Panel容器&#xff0c;然后将button控件排列放置Pane…...

细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的方法

目录 一、DMA基础知识 1、DMA简介 (1)DMA控制器 (2)DMA流 (3)DMA请求 (4)仲裁器 (5)DMA传输属性 2、源地址和目标地址 3、DMA传输模式 4、传输数据量的大小 5、数据宽度 6、地址指针递增 7、DMA工作模式 8、DMA流的优先级别 9、FIFO或直接模式 10、单次传输或突…...

【Unity/Animator动画系统】多层动画状态机实现角色的基本移动

文章目录 前言实现顶层地面状态四方向混合树计算动画所需参数 空中状态分层动画 前言 最近打算做个Rougelike RPG 塔科夫 混搭风格的冒险游戏。暂且就当是一个有随机元素&#xff0c;有基地&#xff0c;死亡会掉落物品的近战塔科夫罢。 花了三天时间&#xff0c;整合了Mixa…...

每日算法一练:剑指offer——栈与队列篇(1)

1.图书整理II 读者来到图书馆排队借还书&#xff0c;图书管理员使用两个书车来完成整理借还书的任务。书车中的书从下往上叠加存放&#xff0c;图书管理员每次只能拿取书车顶部的书。排队的读者会有两种操作&#xff1a; push(bookID)&#xff1a;把借阅的书籍还到图书馆。pop…...

【Java】ArrayList与LinkedList详解!!!

目录 一&#x1f31e;、List 1&#x1f345;.什么是List&#xff1f; 2&#x1f345;.List中的常用方法 二&#x1f31e;、ArrayList 1&#x1f34d;.什么是ArrayList? 2&#x1f34d;.ArrayList的实例化 3&#x1f34d;.ArrayList的使用 4&#x1f34d;.ArrayList的遍…...

怎么用VIM查看UVM源码

利用ctags工具可以建立源码的索引表&#xff0c;在使用VIM或其他文本编辑器时&#xff0c;就可以跳转查看所调用的UVM或VIP的funtcion/task/class等源码了。 首先需要确认ctags安装&#xff0c;一般安装VIM后都有&#xff0c;如果没有可以手动安装。在VIM中可以输入:help ctag…...

数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…...

第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令

文章目录 第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令TCP 设备的 READ 命令READ 修改 $ZA 和 $ZB$ZA 和 READ 命令 第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令 TCP 设备的 READ 命令 从服务器或客户端发出 READ 命令以读取客户端或服务器设置的…...

【C++】哈希表的实现详解

哈希表的实现详解 一、哈希常识1.1、哈希概念1.2、哈希冲突1.3、哈希函数&#xff08;直接定执 除留余数&#xff09;1.4、哈希冲突解决闭散列&#xff08;线性探测 二次探测&#xff09;开散列 二、闭散列哈希表的模拟实现2.1、框架2.2、哈希节点状态的类2.3、哈希表的扩容2…...