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

devtools/2024/11/20 13:12:33/

引言

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++ 容器有所帮助。给我的博客取一个吸引人的标题
在这里插入图片描述


http://www.ppmy.cn/devtools/135479.html

相关文章

苹果ASA归因对接以及API接入

一、归因概要 广告归因&#xff0c;目的是用于衡量广告带来的激活用户的成本以及后续进一步的用户质量表现。 Apple Ads 广告平台是基于 App Store&#xff08;站内广告&#xff09;&#xff0c;同时属于自归因平台&#xff08;通常称为 SAN&#xff09;。这两个因素&#xff…

深入理解 CSS 属性 pointer-events: none

pointer-events 是 CSS 中一个用于控制元素响应鼠标事件&#xff08;或触摸事件&#xff09;的属性。 通过这个属性&#xff0c;我们可以控制元素是否能够接受鼠标事件&#xff0c;例如点击、悬停、拖动等。 其中&#xff0c;pointer-events: none 是 pointer-events 属性的一…

决策树基本 CART Python手写实现

参考资料&#xff1a; https://blog.csdn.net/weixin_45666566/article/details/107954454 https://blog.csdn.net/Elenstone/article/details/105328111 代码如下&#xff1a; #-*- coding:utf-8 -*- import numpy as np import pandas as pd import operatordef loadDataSe…

基于深度学习的文本信息提取方法研究(pytorch python textcnn框架)

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

手机远程控制电脑,让办公更快捷

在数字化办公的浪潮下&#xff0c;远程控制软件已成为连接工作与生活的桥梁。它使得用户能够通过一台设备&#xff08;主控端&#xff09;来操作另一台设备&#xff08;被控端&#xff09;&#xff0c;无论它们是否位于同一局域网内。这种软件广泛应用于远程办公、手机远程控制…

基于物联网的农业环境监测系统开发(本科毕业论文)

基于物联网的农业环境监测系统开发 第一章 绪论 1.1 研究背景及意义 随着全球人口的持续增长和气候变化对农业生产的影响,传统农业模式已无法满足现代社会的需求。物联网技术在农业领域的应用,为农业生产智能化提供了可能,实现了对农业环境的实时监测与精准管理。 农业环境…

蓝桥杯某例题的解决方案和拓展(完全能解决例题本身)

蓝桥杯题目&#xff1a;求1&#xff08;包含&#xff09;直到20230408&#xff08;包含&#xff09;所有自然数的加和。 这个题比较恶心的一点在于&#xff0c;20230408本身没有超过int的上限&#xff0c;但是它的加和是超过int上限的&#xff0c;因此如果直接用int来计算&…

Unity脚本基础规则

Unity脚本基础规则 如何在Unity中创建一个脚本文件&#xff1f; 在Project窗口中的Assets目录下&#xff0c;选择合适的文件夹&#xff0c;右键&#xff0c;选择第一个Create&#xff0c;在新出现的一栏中选择C# Script&#xff0c;此时文件夹内会出现C#脚本图标&#xff0c;…