2025-10-25
编程语言
0

目录

一、容器的分类
二、序列式容器:按顺序存储数据
1. vector:动态数组(最常用)
(1)初始化方式
(2)遍历方式
(3)常用方法
2. list:双向链表
(1)初始化与 vector 类似
(2)遍历:仅支持迭代器和范围 for
(3)独特常用方法
3. deque:双端队列
关键特点
三、关联式容器:自动排序的 “字典”
1. map:键值对映射(键唯一)
(1)初始化方式
(2)遍历方式
(3)常用方法
2. set:仅存储键(键唯一且排序)
关键操作(类比 map)
3. multimap/multiset:允许键重复
四、无序关联式容器:快速查找的 “哈希表”
五、适配器容器:封装后的 “专用工具”
1. stack:栈(先进后出)
2. queue:队列(先进先出)
3. priority\_queue:优先队列(自动排序)
六、新手选择容器的核心原则

对于 C++ 新手来说,容器是编写高效代码的基础工具。容器本质上是用于存储和管理数据的类模板,C++ 标准库(STL)提供了多种容器,每种容器都有独特的底层结构和适用场景。本文将按类别介绍常用容器,包括初始化、遍历和核心操作,帮助新手快速上手。

一、容器的分类

STL 容器主要分为四大类,新手需先明确各类容器的核心特点:

类别代表容器核心特点适用场景
序列式容器vector、list、deque数据按插入顺序存储,可通过索引 / 迭代器访问需按顺序存储、频繁访问或修改数据
关联式容器map、set、multimap、multiset数据自动排序(基于红黑树),通过键值访问需快速查找、排序或去重数据
无序关联式容器unordered_map、unordered_set数据无序存储(基于哈希表),通过键值访问需超快速查找(O (1) 复杂度),不关心排序
适配器容器stack、queue、priority_queue基于其他容器封装,提供特定操作接口需特定数据结构(如栈、队列)的场景

二、序列式容器:按顺序存储数据

序列式容器是新手最易理解的类型,数据存储顺序与插入顺序一致,支持直接访问。

1. vector:动态数组(最常用)

底层结构:动态数组(内存连续),支持快速随机访问,但插入 / 删除尾部外元素效率低。

核心优势:访问速度快(O (1)),内存连续,适合频繁读操作。

(1)初始化方式

c++
#include <vector> using namespace std; // 1. 空vector vector<int> v1; // 2. 初始化n个默认值(int默认0,string默认空) vector<int> v2(5); // 存储:[0,0,0,0,0] vector<string> v3(3); // 存储:["","",""] // 3. 初始化n个指定值 vector<int> v4(4, 10); // 存储:[10,10,10,10] // 4. 用数组/其他容器初始化 int arr[] = {1,2,3,4}; vector<int> v5(arr, arr+4); // 用数组初始化(左闭右开) vector<int> v6(v5.begin(), v5.end());// 用其他vector初始化 vector<int> v7 = {1,2,3,4,5}; // C++11后支持列表初始化(推荐)

(2)遍历方式

c++
// 1. 下标访问(类似数组,仅vector和deque支持) for (int i = 0; i < v7.size(); i++) { cout << v7[i] << " "; // 输出:1 2 3 4 5 } // 2. 迭代器(通用遍历方式,所有容器支持) vector<int>::iterator it; // 普通迭代器(可修改数据) for (it = v7.begin(); it != v7.end(); it++) { *it += 1; // 修改数据(每个元素+1) cout << *it << " "; // 输出:2 3 4 5 6 } // 3. 范围for循环(C++11后,简洁推荐) for (int num : v7) { cout << num << " "; // 输出:2 3 4 5 6 } // 若需修改数据,加引用:for (int& num : v7) { num +=1; }

(3)常用方法

方法功能示例
size()返回元素个数int len = v7.size();(结果为 5)
push_back(x)在尾部添加元素 xv7.push_back(6);(v7 变为 [2,3,4,5,6,6])
pop_back()删除尾部元素(无返回)v7.pop_back();(v7 变回 [2,3,4,5,6])
empty()判断是否为空(空返回 true)if (v7.empty()) { ... }
clear()清空所有元素v7.clear();(size 变为 0,内存不释放)
insert(pos, x)在迭代器 pos 位置插入 xv7.insert(v7.begin()+2, 9);(在第 3 位插入 9)
erase(pos)删除迭代器 pos 位置元素v7.erase(v7.begin()+2);(删除第 3 位元素)

2. list:双向链表

底层结构:双向链表(内存不连续),插入 / 删除效率高(O (1)),但不支持随机访问。

核心优势:适合频繁在中间插入 / 删除数据(如链表操作)。

(1)初始化与 vector 类似

c++
#include <list> list<int> l1; // 空list list<int> l2(3, 5); // 3个5:[5,5,5] list<int> l3 = {1,2,3,4}; // 列表初始化

(2)遍历:仅支持迭代器和范围 for

c++
// 不支持下标访问!必须用迭代器 for (list<int>::iterator it = l3.begin(); it != l3.end(); it++) { cout << *it << " "; // 输出:1 2 3 4 } // 范围for(推荐) for (int num : l3) { cout << num << " "; }

(3)独特常用方法

除size()、empty()、clear()外,list 有链表专属方法:

方法功能示例
push_front(x)在头部添加 xl3.push_front(0);(l3 变为 [0,1,2,3,4])
pop_front()删除头部元素l3.pop_front();(l3 变回 [1,2,3,4])
insert(pos, x)在 pos 位置插入 x(效率高)l3.insert(l3.begin()+1, 9);(无需移动元素)
remove(x)删除所有值为 x 的元素l3.remove(2);(删除所有 2)

3. deque:双端队列

底层结构:分段连续内存(类似 “动态数组的数组”),支持头部和尾部快速操作。

核心优势:兼顾 vector 的随机访问和 list 的首尾操作效率,适合 “队列” 场景。

关键特点

  • 支持下标访问(deque[0])和迭代器遍历;
  • 常用方法:push_front(x)、push_back(x)、pop_front()、pop_back()(首尾操作均为 O (1));
  • 初始化和遍历与 vector 完全一致,新手可先类比 vector 学习。

三、关联式容器:自动排序的 “字典”

关联式容器基于红黑树实现,数据会自动按 “键值” 排序,支持快速查找(O (log n))。核心是 “键(key)” 和 “值(value)” 的映射关系。

1. map:键值对映射(键唯一)

核心特点:每个元素是pair<key, value>(键值对),键不能重复,自动按键排序(默认升序)。

适用场景:需要 “字典” 功能(如姓名→成绩、ID→信息)。

(1)初始化方式

c++
#include <map> using namespace std; // 1. 空map(键int,值string) map<int, string> m1; // 2. 插入键值对(3种方式) m1[1] = "Alice"; // 下标插入(键1对应值Alice) m1.insert(pair<int, string>(2, "Bob")); // pair插入 m1.insert({3, "Charlie"}); // C++11列表插入(推荐) // 3. 直接初始化 map<int, string> m2 = { {1, "Alice"}, {2, "Bob"}, {3, "Charlie"} };

(2)遍历方式

c++
// 1. 迭代器(需访问pair的first和second) map<int, string>::iterator it; for (it = m2.begin(); it != m2.end(); it++) { // it->first是键,it->second是值 cout << "ID:" << it->first << " Name:" << it->second << endl; } // 2. 范围for(推荐,用auto简化类型) for (auto& pair : m2) { // auto自动识别为pair<int, string> cout << "ID:" << pair.first << " Name:" << pair.second << endl; }

(3)常用方法

方法功能示例
size()返回键值对个数int len = m2.size();(结果为 3)
find(key)查找键为 key 的元素,返回迭代器auto it = m2.find(2);(找到返回对应迭代器)
count(key)统计键为 key 的个数(map 中仅 0 或 1)if (m2.count(2) > 0) { ... }(判断键是否存在)
erase(key)删除键为 key 的元素m2.erase(2);(删除 ID=2 的键值对)
clear()清空所有元素m2.clear();

2. set:仅存储键(键唯一且排序)

核心特点:仅存储 “键”(无值),键唯一且自动排序,本质是 “去重 + 排序” 的集合。

适用场景:需要去重或排序的数据(如统计不重复的成绩)。

关键操作(类比 map)

c++
#include <set> set<int> s = {3,1,2,3}; // 初始化,自动去重并排序为[1,2,3] // 遍历 for (int num : s) { cout << num << " "; // 输出:1 2 3 } // 常用方法 s.insert(4); // 插入4(变为[1,2,3,4]) s.erase(2); // 删除2(变为[1,3,4]) if (s.find(3) != s.end()) { // 查找3是否存在 cout << "3 exists"; }

3. multimap/multiset:允许键重复

  • multimap:键可重复,其他与 map 一致(如按键排序);
  • multiset:键可重复,其他与 set 一致;
  • 区别:count(key)可能返回大于 1 的值,find(key)返回第一个匹配的键。

四、无序关联式容器:快速查找的 “哈希表”

无序关联式容器基于哈希表实现,数据无序存储,但查找效率极高(平均 O (1)),适合 “只查不改” 或 “频繁查找” 场景。

核心容器:unordered_map和unordered_set,用法与map/set完全一致,仅两点区别:

  1. 数据无序(遍历顺序与插入顺序无关);
  2. 不支持按键排序相关操作(如lower_bound)。

示例(unordered_map):

c++
#include <unordered_map> unordered_map<int, string> um = { {1, "Alice"}, {2, "Bob"} }; // 遍历(顺序不确定,可能是2→1或1→2) for (auto& pair : um) { cout << pair.first << ":" << pair.second << endl; } // 查找效率比map高(哈希表直接定位) auto it = um.find(1); // 平均O(1)时间

五、适配器容器:封装后的 “专用工具”

适配器容器不直接存储数据,而是基于其他容器(如 vector、deque)封装,提供特定操作接口,新手需掌握核心用法。

1. stack:栈(先进后出)

底层依赖:默认基于 deque,支持push(入栈)、pop(出栈)、top(取栈顶)。

c++
#include <stack> stack<int> st; st.push(1); // 入栈:[1] st.push(2); // 入栈:[1,2] cout << st.top(); // 取栈顶:2 st.pop(); // 出栈:[1] cout << st.size(); // 大小:1

2. queue:队列(先进先出)

底层依赖:默认基于 deque,支持push(入队)、pop(出队)、front(取队首)。

c++
#include <queue> queue<int> q; q.push(1); // 入队:[1] q.push(2); // 入队:[1,2] cout << q.front(); // 取队首:1 q.pop(); // 出队:[2]

3. priority_queue:优先队列(自动排序)

底层依赖:默认基于 vector,数据自动按 “大顶堆” 排序(队首是最大值)。

c++
#include <queue> priority_queue<int> pq; pq.push(3); // 入队:[3] pq.push(1); // 入队后排序:[3,1] pq.push(2); // 入队后排序:[3,2,1] cout << pq.top(); // 取最大值:3 pq.pop(); // 出队后排序:[2,1]

六、新手选择容器的核心原则

  1. 频繁访问数据:选 vector(随机访问快);
  2. 频繁插入 / 删除中间元素:选 list(链表无需移动数据);
  3. 需要队列 / 栈操作:选 queue/stack(适配器简单易用);
  4. 需要字典功能(键值对)
  • 需排序:选 map;
  • 不需排序但要快查:选 unordered_map;
  1. 需要去重
  • 需排序:选 set;
  • 不需排序但要快查:选 unordered_set。

通过以上内容,新手可掌握 C++ 常用容器的核心用法。建议结合实际代码练习(如用 vector 存储学生成绩、用 map 实现字典查询),逐步熟悉各类容器的适用场景,为后续学习算法和数据结构打下基础。

本文作者:司小远

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!