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

STL容器分类总结

在C++的STL(标准模板库)中,容器是用于存储和管理数据的核心组件。STL提供了多种容器,根据其底层实现和特性,可以分为四大类。

	1序列容器:vector、deque、list、forward_list、array、string2关联容器:set、multisat、map、multimap3无序关联容器:unordered_set、unordered_multiset、unordered_map、unordered_multimap4容器适配器:stack、queue、priority_queue

以下是STL容器的详细分类和介绍:

目录

  • 一、序列容器(Sequence Containers)
    • ***序列容器核心操作对比
    • ***序列容器选择指南
    • *性能优化建议
    • 1. std::vector(动态数组)
    • 2. std::deque(双端队列)
    • 3. std::list(双向链表)
    • 4. std::forward_list(单向链表,C++11)
    • 5. std::array(固定大小数组,C++11)
    • 6. string(字符串容器)
  • 二、关联容器(Associative Containers)
    • *关联容器的主要类型
    • **关联容器的核心特性
    • 1. set(唯一键集合)
    • 2. multiset(可重复键集合)
    • 3. map(唯一键值对映射)
    • 4. multimap(可重复键值对映射)
    • 关联容器的操作示例
  • 三、无序关联容器(Unordered Associative Containers)
    • 1. unordered_set(唯一键集合)
    • 2. unordered_multiset(可重复键集合)
    • 3. unordered_map(唯一键值对映射)
    • 4. unordered_multimap(可重复键值对映射)
    • 无序关联容器的操作示例
  • 四、容器适配器(Container Adapters)
    • 1、基本特性
    • *应用场景:
    • 1. stack(栈)
    • 2. queue(队列)
    • 3. priority_queue(优先级队列)
  • 五、如何选择容器?

一、序列容器(Sequence Containers)

序列容器是C++标准模板库(STL)中用于存储线性数据集合的容器类型,它们按照严格的线性顺序组织元素,支持通过位置(索引或迭代器)访问元素。以下是C++中主要的序列容器及其核心特性:
序列容器按元素插入的顺序存储数据,支持随机访问或顺序访问。

***序列容器核心操作对比

操作vectordequelistforward_listarray
随机访问O(1)O(1)不支持O(n)不支持O(1)
尾部插入/删除O(1)O(1)O(1)不支持不支持
头部插入/删除O(n)O(1)O(1)O(1)不支持
中间插入/删除O(n)O(n)O(1)O(n)不支持
内存连续性部分
大小动态性

***序列容器选择指南

1需要随机访问:

  • 优先选择vector(除非需要频繁头部操作)
  • 如果需要频繁头部操作,选择deque

2需要频繁中间插入/删除:

  • 选择list或forward_list(根据是否需要反向遍历)

3需要固定大小数组:

  • 选择array(比内置数组更安全)

4内存敏感场景:

  • 考虑forward_list(比list更节省内存)
  • 或预先分配足够空间的vector(避免多次扩容)

5需要迭代器稳定性:

  • list和forward_list的迭代器在插入/删除时不会失效(除非指向被删除的元素)
  • 其他容器的迭代器在插入/删除时可能失效

*性能优化建议

1vector预分配:

std::vector<int> v;
v.reserve(1000); // 预先分配空间,避免多次扩容

2使用emplace代替push:

std::vector<std::pair<int, std::string>> v;
v.emplace_back(1, "hello"); // 原地构造,避免临时对象

3避免不必要的拷贝:

	使用引用或移动语义传递容器

4考虑迭代器稳定性需求:

	如果需要频繁插入/删除且要保持迭代器有效,选择链表类容器

1. std::vector(动态数组)

底层实现:连续内存,动态扩容(通常翻倍)。
特点:1动态增长的连续内存数组2支持快速随机访问(O(1)3尾部插入/删除高效(平均O(1)4中间插入/删除低效(O(n))适用场景:1需要频繁随机访问2尾部操作多于中间操作3大小动态变化但不需要频繁中间插入
#include <vector>
std::vector<int> v = {1, 2, 3}; // 初始化
v.push_back(4);                 // 尾部插入
int x = v[1];                   // 随机访问

2. std::deque(双端队列)

底层实现:分段连续内存,类似多个vector的组合。
特点:1分段连续内存结构2支持头尾高效插入/删除(O(1)-----3支持随机访问(O(1)4中间操作效率低于vector-----
适用场景:需要频繁在头部和尾部操作需要随机访问但中间操作较少
#include <deque>
std::deque<int> d = {1, 2, 3};
d.push_front(0);  // 头部插入
d.push_back(4);   // 尾部插入

3. std::list(双向链表)

底层实现:双向链表,节点分散在内存中。
特点:1双向链表,节点分散在内存中。2支持高效的插入/删除操作(O(1)),但需要遍历到指定位置(O(n))。3不支持随机访问。4内存不连续,适合频繁插入/删除的场景。5额外内存开销(每个节点存储前后指针)适用场景:需要频繁插入/删除不关心随机访问的场景,如链表操作。
#include <list>
std::list<int> l = {1, 2, 3};
auto it = l.begin();
++it; // 移动到第二个元素
l.insert(it, 10); // 在第二个位置插入

4. std::forward_list(单向链表,C++11)

底层实现:单向链表,节点分散在内存中。
特点:1仅支持单向遍历,比list更节省内存。2插入/删除操作高效(O(1)),但需要遍历到指定位置(O(n))。3不支持随机访问。4没有size()成员函数(需要遍历计算)---适用场景:1需要单向链表特性2内存敏感且不需要反向遍历
#include <forward_list>
std::forward_list<int> fl = {1, 2, 3};
fl.push_front(0); // 只能在头部插入

5. std::array(固定大小数组,C++11)

底层实现:连续内存,大小在编译时确定。
特点:1固定大小的连续内存数组2编译时确定大小3支持随机访问(O(1)4不支持动态增长适用场景:1需要固定大小数组2需要STL容器的接口和安全性如替代普通数组。
#include <array>
std::array<int, 3> arr = {1, 2, 3};
int x = arr[1]; // 随机访问

6. string(字符串容器)

底层实现:本质上是字符的vector,支持动态扩容。
特点:1支持丰富的字符串操作函数(如拼接、查找、替换等)。2动态扩容,适合需要频繁修改字符串的场景。适用场景:字符串处理,如文本操作。

二、关联容器(Associative Containers)

关联容器通过键(key)存储和检索元素,元素默认按升序排列。
在C++中,关联容器是一种用于存储和管理键值对(或仅键)数据的容器,其主要特点是能够通过键快速查找值。关联容器与序列容器不同,它们不保证元素的存储顺序(有序关联容器除外),而是根据键的排序方式或哈希值来组织数据。以下是C++中关联容器的核心概念和类型

*关联容器的主要类型

1有序关联容器:

std::map:存储唯一的键值对,按键自动排序。
std::multimap:存储键值对,允许键重复,按键自动排序。
std::set:存储唯一的键(无值),按键自动排序。
std::multiset:存储键,允许键重复,按键自动排序。

这些容器通常基于平衡二叉搜索树(如红黑树)实现,查找、插入和删除操作的时间复杂度为O(log n)。

2无序关联容器(C++11引入):

std::unordered_map:存储唯一的键值对,不保证顺序,使用哈希表实现。
std::unordered_multimap:存储键值对,允许键重复,不保证顺序,使用哈希表实现。
std::unordered_set:存储唯一的键,不保证顺序,使用哈希表实现。
std::unordered_multiset:存储键,允许键重复,不保证顺序,使用哈希表实现。

无序关联容器的查找、插入和删除操作的平均时间复杂度为O(1),但在最坏情况下可能退化为O(n)。

**关联容器的核心特性

1键值对存储:

	map和multimap存储键值对,通过键访问值。set和multiset仅存储键,键本身即标识元素。

2自动排序(有序关联容器):

	元素按键的顺序自动排序,默认使用<运算符进行比较。可自定义比较函数或函数对象来改变排序规则。

3高效查找:

	通过键快速查找元素,时间复杂度通常为O(log n)(有序)或O(1)(无序)。

4不允许键重复(除multimap和multiset外):

	插入重复键时,map和set会忽略新元素,而multimap和multiset会保留所有重复键。

1. set(唯一键集合)

底层实现:红黑树(平衡二叉搜索树)。
特点:1键唯一,元素有序。2插入、删除、查找的时间复杂度为O(log n)。适用场景:需要唯一键且有序的场景,如去重和排序。---

2. multiset(可重复键集合)

底层实现:红黑树。
特点:1键可重复,元素有序。2插入、删除、查找的时间复杂度为O(log n)。适用场景:需要可重复键且有序的场景,如统计词频。---

3. map(唯一键值对映射)

底层实现:红黑树。
特点:1键唯一,键值对有序。2插入、删除、查找的时间复杂度为O(log n)。适用场景:需要唯一键且有序的键值对场景,如字典。----

4. multimap(可重复键值对映射)

底层实现:红黑树。
特点:1键可重复,键值对有序。2插入、删除、查找的时间复杂度为O(log n)。适用场景:需要可重复键且有序的键值对场景,如多值映射。-----

关联容器的操作示例

#include <iostream>
#include <map>
#include <set>
#include <unordered_map>int main() {// 有序关联容器示例std::map<std::string, int> ages;ages["Alice"] = 30;ages["Bob"] = 25;for (const auto& entry : ages) {std::cout << entry.first << ": " << entry.second << std::endl;}std::set<int> numbers = {3, 1, 4, 1, 5};for (int num : numbers) {std::cout << num << " "; // 输出: 1 3 4 5(自动去重并排序)}// 无序关联容器示例std::unordered_map<std::string, int> scores;scores["Alice"] = 90;scores["Bob"] = 85;for (const auto& entry : scores) {std::cout << entry.first << ": " << entry.second << std::endl;}return 0;
}

三、无序关联容器(Unordered Associative Containers)

无序关联容器通过哈希表实现,元素无序,但插入、删除和查找的平均时间复杂度为O(1)。

1. unordered_set(唯一键集合)

底层实现:哈希表。
特点:1键唯一,元素无序。2插入、删除、查找的平均时间复杂度为O(1),最坏为O(n)。适用场景:需要快速查找且不关心顺序的场景,如哈希集合

2. unordered_multiset(可重复键集合)

底层实现:哈希表。
特点:1键可重复,元素无序。2插入、删除、查找的平均时间复杂度为O(1),最坏为O(n)。适用场景:需要快速查找且键可重复的场景,如哈希多值集合。

3. unordered_map(唯一键值对映射)

底层实现:哈希表。
特点:1键唯一,键值对无序。2插入、删除、查找的平均时间复杂度为O(1),最坏为O(n)。适用场景:需要快速查找且不关心键顺序的键值对场景,如哈希字典。

4. unordered_multimap(可重复键值对映射)

底层实现:哈希表。
特点:1键可重复,键值对无序。2插入、删除、查找的平均时间复杂度为O(1),最坏为O(n)。适用场景:需要快速查找且键可重复的键值对场景,如哈希多值映射。

无序关联容器的操作示例

#include <iostream>
#include <unordered_map>
#include <unordered_set>int main() {// unordered_map示例std::unordered_map<std::string, int> ages;ages["Alice"] = 30;ages["Bob"] = 25;ages["Charlie"] = 35;for (const auto& entry : ages) {std::cout << entry.first << ": " << entry.second << std::endl;}// unordered_set示例std::unordered_set<int> numbers = {3, 1, 4, 1, 5};for (int num : numbers) {std::cout << num << " "; // 输出可能是: 3 1 4 5(顺序不确定)}// unordered_multimap示例std::unordered_multimap<std::string, int> scores;scores.insert({"Alice", 90});scores.insert({"Bob", 85});scores.insert({"Alice", 95}); // 允许重复键auto range = scores.equal_range("Alice");for (auto it = range.first; it != range.second; ++it) {std::cout << it->first << ": " << it->second << std::endl;}return 0;
}

四、容器适配器(Container Adapters)

容器适配器是基于其他容器实现的,提供了特定的接口和行为。
在C++中,容器适配器(Container Adapter)是一种特殊的容器类型,它通过封装现有的容器并限制其接口,提供特定数据结构的特性(如栈、队列、优先队列等)。以下是容器适配器的核心概念:

1、基本特性

封装与限制:容器适配器不是独立的容器,而是基于其他容器(如deque、vector、list)实现的。它们通过封装这些基础容器,并仅暴露符合目标数据结构特性的操作,从而限制用户只能按特定方式操作数据。

特定数据结构行为:容器适配器提供了栈、队列、优先队列等经典数据结构的操作接口,使得用户可以直接使用这些数据结构,而无需手动实现。

*应用场景:

栈:适用于需要后进先出操作的场景,如函数调用栈、括号匹配、表达式求值(逆波兰式)等。
队列:适用于需要先进先出操作的场景,如任务调度、BFS广度优先搜索、缓冲池等。
优先队列:适用于需要按优先级处理元素的场景,如任务优先级调度、Dijkstra最短路径算法、Top K问题等。

1. stack(栈)

底层实现:默认基于deque,也可基于vector或list。
特点:1后进先出(LIFO)结构。2支持操作:push(插入元素到栈顶)、pop(删除栈顶元素)、top(返回栈顶元素)、empty(检查栈是否为空)、size(返回栈中元素的数量)。适用场景:需要栈行为的场景,如函数调用栈。

2. queue(队列)

底层实现:默认基于deque,也可基于list。注意,vector不能作为queue的底层容器,因为它不支持在头部进行高效的插入和删除操作。
特点:1先进先出(FIFO)结构。2支持操作:push(插入元素到队尾)、pop(删除队头元素)、front(返回队头元素)、back(返回队尾元素)、empty(检查队列是否为空)、size(返回队列中元素的数量)。适用场景:需要队列行为的场景,如任务调度。

3. priority_queue(优先级队列)

底层实现:vector,并使用make_heap、push_heap和pop_heap来维护堆结构。
特点:1元素按优先级排序,默认最大值优先。2支持操作:push(插入元素并维护优先级顺序)、pop(删除优先级最高的元素)、top(返回优先级最高的元素)、empty(检查队列是否为空)、size(返回队列中元素的数量)。此外,可以通过指定比较函数来改变元素的优先级顺序。适用场景:需要优先级队列的场景,如任务优先级调度。

五、如何选择容器?

场景需求推荐容器说明
需要随机访问vector、deque、arrayvector适合频繁访问,deque适合头部/尾部操作,array适合固定大小。
需要频繁插入/删除list、forward_listlist适合双向操作,forward_list适合单向操作。
需要唯一键且有序set、map键唯一且有序,适合字典或集合操作。
需要可重复键且有序multiset、multimap键可重复且有序,适合多值映射。
需要快速查找且不关心顺序unordered_set、unordered_map平均O(1)时间复杂度,适合哈希操作。
需要栈行为stack基于其他容器实现,默认deque。
需要队列行为queue基于其他容器实现,默认deque。
需要优先级队列priority_queue基于堆实现,默认最大值优先。

六、示例代码

#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
using namespace std;int main() {// 序列容器示例vector<int> vec = {1, 2, 3};list<string> lst = {"a", "b", "c"};// 关联容器示例map<string, int> m = {{"apple", 10}, {"banana", 20}};m["orange"] = 30;// 无序关联容器示例unordered_map<int, string> um = {{1, "one"}, {2, "two"}};// 容器适配器示例stack<int> stk;stk.push(10);stk.push(20);cout << "Stack top: " << stk.top() << endl; // 输出:20queue<int> q;q.push(100);q.push(200);cout << "Queue front: " << q.front() << endl; // 输出:100priority_queue<int> pq;pq.push(30);pq.push(10);pq.push(20);cout << "Priority queue top: " << pq.top() << endl; // 输出:30return 0;
}

七、总结

序列容器:适合需要按顺序存储和访问数据的场景。
关联容器:适合需要通过键快速查找数据的场景,且键有序。
无序关联容器:适合需要通过键快速查找数据的场景,但不关心顺序。
容器适配器:适合需要特定行为(如栈、队列、优先级队列)的场景。

通过合理选择容器,可以显著提高代码的效率和可读性。根据具体需求(如是否需要随机访问、是否需要有序、是否需要快速查找等)选择合适的容器是关键

相关文章:

  • 探索RAGFlow:解锁生成式AI的无限潜能(2/6)
  • 第二十章 Centos8的使用
  • DP刷题练习(三)
  • linux thermal framework(4)_thermal governor
  • Linux 忘记root密码如何解决-linux025
  • 2.1 Windows VS2019编译FFmpeg 4.4.1
  • PCL 生成圆柱面点云
  • 人工智能-准确率(Precision)、召回率(Recall) 和 F1 分数
  • YOLO优化之双池化下采样融合块、注意力引导逆残差块
  • 第20篇:数据库中间件的热点 Key 缓存一致性策略与分布式协调机制
  • Spring Boot 整合 Swagger 快速生成 API 文档的最佳实践
  • Axure应用交互设计:中继器数据向多种类型元件赋值
  • jxWebUI--简单易用的webUI库
  • Iceberg与Hive集成深度
  • linux多线程之条件变量
  • 学习昇腾开发的第三天--将服务器连接网络
  • Android 与 ESP-01 WIFI模块通信
  • HTTP协议简易入门
  • Vue3相关知识3
  • JS当中怎么定义一个类
  • 网站建设全包广/百度百度网址大全
  • 网站建设需要什么研究条件/企业如何做网站
  • 龙岩房地产信息网/青岛网站优化公司哪家好
  • 提供网站建设报价/移动建站优化
  • 福州网红景点/百度热搜seo
  • 都安做网站/视频号下载器手机版