# C++ STL 常用容器方法全面总结vector / map / set / unordered_map / unordered_set

本文系统总结 C++ STL 中最常用的五种容器------vectormapsetunordered_mapunordered_set 的常用方法,涵盖构造、迭代、容量、元素访问、查找、修改等操作,并附带代码示例与时间复杂度说明,最后给出一张横向对比表,帮助你在实际开发中快速查阅与选型。


一、vector 动态数组

1.1 简介

vector 是一段连续内存的动态数组,支持随机访问,尾部增删效率高(均摊 O(1)),中间/头部增删为 O(n)。它是日常开发中使用频率最高的容器。

头文件: <vector>

1.2 构造

cpp 复制代码
vector<int> v1;                    // 空容器
vector<int> v2(n);                 // n 个默认值(0)
vector<int> v3(n, 10);             // n 个 10
vector<int> v4 = {1, 2, 3, 4, 5}; // 初始化列表
vector<int> v5(v4);                // 拷贝构造
vector<int> v6(v4.begin(), v4.begin() + 3); // 区间构造

1.3 迭代器

方法 说明
begin() / end() 首元素 / 尾后迭代器
rbegin() / rend() 反向首 / 反向尾后
cbegin() / cend() 只读版本(C++11)
cpp 复制代码
for (auto it = v.begin(); it != v.end(); ++it)
    cout << *it << " ";
// 范围 for 循环
for (const auto& x : v)
    cout << x << " ";

1.4 容量与大小

方法 说明
size() 当前元素个数
capacity() 已分配的存储容量
empty() 是否为空
resize(n) / resize(n, val) 改变大小,多则填默认值/val
reserve(n) 预分配容量(不改变 size)
shrink_to_fit() 请求释放未使用内存

技巧: 已知最终元素数量时,提前 reserve() 可避免多次重新分配,显著提升性能。

1.5 元素访问

方法 说明
operator[i] 下标访问(不越界检查
at(i) 下标访问(越界抛异常
front() 首元素
back() 尾元素
data() 底层数组指针
cpp 复制代码
v[0]    // 快速访问
v.at(0) // 安全访问,越界抛 std::out_of_range

1.6 修改操作

方法 说明
push_back(val) 尾部添加元素
pop_back() 尾部删除元素
insert(pos, val) 在 pos 处插入
insert(pos, n, val) 插入 n 个 val
insert(pos, first, last) 插入区间
emplace(pos, args...) 原地构造插入(C++11)
emplace_back(args...) 原地构造尾插(C++11)
erase(pos) / erase(first, last) 删除元素
clear() 清空
swap(other) 交换两个容器
assign(n, val) / assign(first, last) 赋值替换

emplace vs push_back: emplace_back 直接在内存中原地构造对象,避免了临时对象的拷贝/移动,适合复杂对象。

1.7 完整示例

cpp 复制代码
#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3};
    v.push_back(4);        // {1,2,3,4}
    v.emplace_back(5);     // {1,2,3,4,5}
    v.insert(v.begin(), 0); // {0,1,2,3,4,5}
    v.pop_back();           // {0,1,2,3,4}
    v.erase(v.begin());     // {1,2,3,4}

    for (int i = 0; i < v.size(); i++)
        cout << v[i] << " ";  // 1 2 3 4
    return 0;
}

1.8 时间复杂度

操作 复杂度
随机访问 operator[] / at O(1)
push_back / pop_back 均摊 O(1)
insert / erase(中间) O(n)
查找(无序) O(n)

二、map 有序映射

2.1 简介

map 是基于红黑树 的有序键值对容器,键唯一且自动排序。查找、插入、删除均为 O(log n)。键需支持 operator<

头文件: <map>

2.2 构造

cpp 复制代码
map<int, string> m1;                        // 空
map<int, string> m2 = {{1, "apple"}, {2, "banana"}}; // 初始化列表
map<int, string> m3(m2);                   // 拷贝
map<int, string> m4(m2.begin(), m2.end()); // 区间构造

2.3 迭代器

map 的迭代器是双向迭代器,按 key 升序遍历。

cpp 复制代码
for (auto& [key, val] : m)  // C++17 结构化绑定
    cout << key << " -> " << val << endl;

2.4 容量

方法 说明
size() 元素个数
empty() 是否为空
max_size() 最大容量

2.5 元素访问

方法 说明
operator[key] 访问/插入(key 不存在则插入默认值
at(key) 访问(key 不存在则抛异常

注意: operator[] 在 key 不存在时会自动插入默认构造的值,这在只想查找时会意外修改容器。若仅查找,应使用 at()find()

2.6 查找

方法 说明
find(key) 返回指向 key 的迭代器,未找到返回 end()
count(key) key 的个数(map 中为 0 或 1)
contains(key) 是否存在(C++20)
lower_bound(key) 第一个 >= key 的迭代器
upper_bound(key) 第一个 > key 的迭代器
equal_range(key) 返回 [lower, upper) 区间
cpp 复制代码
auto it = m.find(2);
if (it != m.end())
    cout << it->second << endl; // banana

if (m.count(1))  // 存在返回 1
    cout << "found" << endl;

2.7 修改操作

方法 说明
insert({key, val}) 插入键值对(key 存在则不覆盖
insert_or_assign(key, val) 插入或赋值(C++17)
emplace(key, val) 原地构造
erase(key) / erase(pos) 删除
clear() 清空
swap(other) 交换
cpp 复制代码
map<int, string> m;
m[1] = "apple";         // operator[] 插入+赋值
m.insert({2, "banana"}); // insert 插入
m.emplace(3, "cherry");  // 原地构造
m.erase(1);              // 删除 key=1

2.8 时间复杂度

操作 复杂度
查找 / 插入 / 删除 O(log n)
遍历 O(n)

三、set 有序集合

3.1 简介

set 是基于红黑树 的有序集合,元素唯一且自动排序。与 map 类似,但只存 key 不存 value。底层实现与 map 相同,操作复杂度一致。

头文件: <set>

3.2 构造

cpp 复制代码
set<int> s1;                       // 空
set<int> s2 = {3, 1, 4, 1, 5};    // {1,3,4,5}(自动去重排序)
set<int> s3(s2);                  // 拷贝
set<int> s4(s2.begin(), s2.end()); // 区间构造
set<int, greater<int>> s5 = {3, 1, 2}; // 降序排列 {3,2,1}

3.3 容量

方法 说明
size() 元素个数
empty() 是否为空

3.4 迭代器

按升序遍历(或自定义排序),双向迭代器。

cpp 复制代码
for (const auto& x : s)
    cout << x << " "; // 1 3 4 5

3.5 查找

方法 说明
find(val) 返回指向 val 的迭代器
count(val) 个数(0 或 1)
contains(val) 是否存在(C++20)
lower_bound(val) 第一个 >= val
upper_bound(val) 第一个 > val
equal_range(val) [lower, upper) 区间
cpp 复制代码
set<int> s = {1, 3, 5, 7, 9};
auto it = s.lower_bound(5); // 指向 5
auto it2 = s.upper_bound(5); // 指向 7

3.6 修改操作

方法 说明
insert(val) 插入元素
emplace(args...) 原地构造插入
erase(val) / erase(pos) 删除
clear() 清空
swap(other) 交换
cpp 复制代码
set<int> s;
s.insert(3);
s.insert(1);
s.insert(3); // 重复,不会插入
s.erase(1);

3.7 时间复杂度

操作 复杂度
查找 / 插入 / 删除 O(log n)
遍历 O(n)

四、unordered_map 哈希映射

4.1 简介

unordered_map 是基于哈希表 的键值对容器,键唯一但无序 。平均查找、插入、删除为 O(1),最坏情况为 O(n)(哈希冲突)。当不需要有序性时,性能优于 map

头文件: <unordered_map>

4.2 构造

cpp 复制代码
unordered_map<int, string> m1;
unordered_map<int, string> m2 = {{1, "apple"}, {2, "banana"}};
unordered_map<int, string> m3(m2);

4.3 容量

方法 说明
size() 元素个数
empty() 是否为空
max_size() 最大容量

4.4 元素访问

方法 说明
operator[key] 访问/插入(key 不存在则插入默认值)
at(key) 访问(不存在抛异常)

4.5 查找

方法 说明
find(key) 返回迭代器,未找到返回 end()
count(key) 0 或 1
contains(key) 是否存在(C++20)
equal_range(key) 返回匹配范围

注意: unordered_map 没有 lower_bound / upper_bound,因为元素无序。

4.6 修改操作

方法 说明
insert({key, val}) 插入
emplace(key, val) 原地构造
erase(key) / erase(pos) 删除
clear() 清空
swap(other) 交换

4.7 桶与哈希策略

方法 说明
bucket_count() 桶数量
bucket(key) key 所在桶编号
bucket_size(n) 第 n 个桶的元素数
load_factor() 装载因子 = size / bucket_count
max_load_factor() 最大装载因子阈值
rehash(n) 设置桶数(rehash)
reserve(n) 预留空间(自动 rehash)
cpp 复制代码
unordered_map<int, string> m;
m.reserve(1000); // 预留空间,减少 rehash 次数

4.8 完整示例

cpp 复制代码
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;

int main() {
    unordered_map<string, int> wordCount;
    wordCount["hello"] = 1;
    wordCount["world"] = 2;
    wordCount.emplace("cpp", 3);

    // 遍历(无序)
    for (const auto& [word, count] : wordCount)
        cout << word << ": " << count << endl;

    // 查找
    if (wordCount.find("hello") != wordCount.end())
        cout << "found hello" << endl;

    return 0;
}

4.9 时间复杂度

操作 平均 最坏
查找 / 插入 / 删除 O(1) O(n)
遍历 O(n) O(n)

五、unordered_set 哈希集合

5.1 简介

unordered_set 是基于哈希表 的无序集合,元素唯一,不排序。与 unordered_map 底层实现一致,但仅存 key。平均 O(1) 的增删查。

头文件: <unordered_set>

5.2 构造

cpp 复制代码
unordered_set<int> s1;
unordered_set<int> s2 = {1, 3, 5, 3, 7}; // {1,3,5,7}(去重,无序)
unordered_set<int> s3(s2);

5.3 容量

方法 说明
size() 元素个数
empty() 是否为空

5.4 迭代器

遍历顺序不确定(由哈希函数决定),前向迭代器。

cpp 复制代码
for (const auto& x : s)
    cout << x << " "; // 顺序不确定,如 5 1 7 3

5.5 查找

方法 说明
find(val) 返回迭代器
count(val) 0 或 1
contains(val) 是否存在(C++20)
equal_range(val) 匹配范围

5.6 修改操作

方法 说明
insert(val) 插入
emplace(args...) 原地构造
erase(val) / erase(pos) 删除
clear() 清空
swap(other) 交换

5.7 桶与哈希策略

方法 说明
bucket_count() 桶数量
bucket(val) val 所在桶
load_factor() 装载因子
rehash(n) 重新哈希
reserve(n) 预留空间

5.8 完整示例

cpp 复制代码
#include <unordered_set>
#include <iostream>
using namespace std;

int main() {
    unordered_set<int> s = {5, 3, 1, 7, 3}; // {1,3,5,7}
    s.insert(9);
    s.erase(3);

    for (const auto& x : s)
        cout << x << " "; // 无序输出

    cout << (s.count(7) ? "yes" : "no") << endl;
    return 0;
}

5.9 时间复杂度

操作 平均 最坏
查找 / 插入 / 删除 O(1) O(n)
遍历 O(n) O(n)

六、横向对比总表

特性 vector map set unordered_map unordered_set
底层结构 动态数组 红黑树 红黑树 哈希表 哈希表
有序性 按插入序 按 key 排序 排序 无序 无序
元素唯一性 可重复 key 唯一 唯一 key 唯一 唯一
随机访问 O(1) operator[]/at 不支持 operator[]/at 不支持
查找 O(n) O(log n) O(log n) O(1) 平均 O(1) 平均
插入 尾部 O(1) O(log n) O(log n) O(1) 平均 O(1) 平均
删除 尾部 O(1) O(log n) O(log n) O(1) 平均 O(1) 平均
头文件 <vector> <map> <set> <unordered_map> <unordered_set>
迭代器类型 随机访问 双向 双向 前向 前向
lower/upper_bound 支持 支持 支持 不支持 不支持
内存开销 较大 较大 中等 中等

七、选型建议

  1. 需要随机访问 + 尾部增删vector(默认首选)
  2. 需要有序键值对map
  3. 需要有序去重集合set
  4. 需要高频查找键值对(不需排序)unordered_map
  5. 需要高频查找去重集合(不需排序)unordered_set
  6. 元素数量已知 → 提前 reserve() 减少 rehash/扩容开销
  7. 自定义类型作为 keymap/set 需定义 operator<unordered_map/unordered_set 需提供哈希函数和 operator==

自定义类型作为 unordered_set key 的示例

cpp 复制代码
#include <unordered_set>
#include <string>
using namespace std;

struct Point {
    int x, y;
    bool operator==(const Point& o) const {
        return x == o.x && y == o.y;
    }
};

// 自定义哈希函数
struct PointHash {
    size_t operator()(const Point& p) const {
        return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1);
    }
};

int main() {
    unordered_set<Point, PointHash> points;
    points.insert({1, 2});
    points.insert({3, 4});
    return 0;
}

八、通用方法速查

以下方法五个容器基本都支持

方法 说明
size() 元素个数
empty() 是否为空
clear() 清空
swap(other) 交换两个容器
begin() / end() 迭代器
insert(...) 插入
emplace(...) 原地构造插入
erase(...) 删除
find(key) 查找(vector 无此方法)
count(key) 计数(vector 无此方法)

总结

场景 推荐容器
动态数组 / 栈 / 缓冲区 vector
有序字典 / 范围查询 map
有序去重 / 范围查询 set
高频 KV 查找 / 计数 unordered_map
高频去重查找 unordered_set

核心原则: 需要有序 → 选红黑树系列(map/set);追求性能且无需排序 → 选哈希系列(unordered_map/unordered_set);需要随机访问 + 尾部增删 → 选 vector

希望本文能帮助你在日常开发中快速查阅和选型。如有错误或遗漏,欢迎评论区交流指正!


本文档参考标准: cppreference.com

相关推荐
daad7771 小时前
802.11 前导码与 STF 深度解析(含检测算法与 5G 对比
人工智能·算法·5g·wifi·802.11·前导码
Navigator_Z2 小时前
LeetCode //C - 1203. Sort Items by Groups Respecting Dependencies
c语言·算法·leetcode
我变成萤火虫3 小时前
2026 ICPC沈阳邀请赛Vp补题
数据结构·c++·算法·贪心算法·stl·排序算法·动态规划
风起洛阳@不良使3 小时前
中级软考(软件攻城狮)第3章知识点——数据结构与数据运算(线性结构+非线性结构)
数据结构·算法·链表
AndrewHZ3 小时前
图像处理入门009 | OpenCV 图像读取与显示:imread/imshow 全解析
图像处理·python·opencv·算法·计算机视觉·图像显示
学计算机的计算基3 小时前
TCP 传输层硬核整理:三次握手、四次挥手、拥塞控制一次讲透
java·网络·笔记·网络协议·算法
xx~t4 小时前
嵌入式学习22
数据结构·学习·算法·排序算法
我是苏苏4 小时前
C#基础:不写for循环的五种方式
数据结构·算法·c#