对于 C++ 新手来说,容器是编写高效代码的基础工具。容器本质上是用于存储和管理数据的类模板,C++ 标准库(STL)提供了多种容器,每种容器都有独特的底层结构和适用场景。本文将按类别介绍常用容器,包括初始化、遍历和核心操作,帮助新手快速上手。
STL 容器主要分为四大类,新手需先明确各类容器的核心特点:
| 类别 | 代表容器 | 核心特点 | 适用场景 |
|---|---|---|---|
| 序列式容器 | vector、list、deque | 数据按插入顺序存储,可通过索引 / 迭代器访问 | 需按顺序存储、频繁访问或修改数据 |
| 关联式容器 | map、set、multimap、multiset | 数据自动排序(基于红黑树),通过键值访问 | 需快速查找、排序或去重数据 |
| 无序关联式容器 | unordered_map、unordered_set | 数据无序存储(基于哈希表),通过键值访问 | 需超快速查找(O (1) 复杂度),不关心排序 |
| 适配器容器 | stack、queue、priority_queue | 基于其他容器封装,提供特定操作接口 | 需特定数据结构(如栈、队列)的场景 |
序列式容器是新手最易理解的类型,数据存储顺序与插入顺序一致,支持直接访问。
底层结构:动态数组(内存连续),支持快速随机访问,但插入 / 删除尾部外元素效率低。
核心优势:访问速度快(O (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后支持列表初始化(推荐)
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; }
| 方法 | 功能 | 示例 |
|---|---|---|
| size() | 返回元素个数 | int len = v7.size();(结果为 5) |
| push_back(x) | 在尾部添加元素 x | v7.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 位置插入 x | v7.insert(v7.begin()+2, 9);(在第 3 位插入 9) |
| erase(pos) | 删除迭代器 pos 位置元素 | v7.erase(v7.begin()+2);(删除第 3 位元素) |
底层结构:双向链表(内存不连续),插入 / 删除效率高(O (1)),但不支持随机访问。
核心优势:适合频繁在中间插入 / 删除数据(如链表操作)。
c++#include <list>
list<int> l1; // 空list
list<int> l2(3, 5); // 3个5:[5,5,5]
list<int> l3 = {1,2,3,4}; // 列表初始化
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 << " ";
}
除size()、empty()、clear()外,list 有链表专属方法:
| 方法 | 功能 | 示例 |
|---|---|---|
| push_front(x) | 在头部添加 x | l3.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) |
底层结构:分段连续内存(类似 “动态数组的数组”),支持头部和尾部快速操作。
核心优势:兼顾 vector 的随机访问和 list 的首尾操作效率,适合 “队列” 场景。
关联式容器基于红黑树实现,数据会自动按 “键值” 排序,支持快速查找(O (log n))。核心是 “键(key)” 和 “值(value)” 的映射关系。
核心特点:每个元素是pair<key, value>(键值对),键不能重复,自动按键排序(默认升序)。
适用场景:需要 “字典” 功能(如姓名→成绩、ID→信息)。
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"}
};
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;
}
| 方法 | 功能 | 示例 |
|---|---|---|
| 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(); |
核心特点:仅存储 “键”(无值),键唯一且自动排序,本质是 “去重 + 排序” 的集合。
适用场景:需要去重或排序的数据(如统计不重复的成绩)。
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";
}
无序关联式容器基于哈希表实现,数据无序存储,但查找效率极高(平均 O (1)),适合 “只查不改” 或 “频繁查找” 场景。
核心容器:unordered_map和unordered_set,用法与map/set完全一致,仅两点区别:
示例(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)封装,提供特定操作接口,新手需掌握核心用法。
底层依赖:默认基于 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
底层依赖:默认基于 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]
底层依赖:默认基于 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]
通过以上内容,新手可掌握 C++ 常用容器的核心用法。建议结合实际代码练习(如用 vector 存储学生成绩、用 map 实现字典查询),逐步熟悉各类容器的适用场景,为后续学习算法和数据结构打下基础。
本文作者:司小远
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!