# 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

相关推荐
小玮看世界5 小时前
[Python]OD算法在OD实际运用转化参考清单
开发语言·python·算法
黎阳之光5 小时前
数字孪生赋能全域水网,实现水资源管控与节水降碳双向提升
人工智能·物联网·算法·安全·数字孪生
随意起个昵称5 小时前
【BFS】冰面滑行
算法·宽度优先
(Charon)6 小时前
【C++】定时器进阶:使用最小堆管理定时任务
c++·算法
hansang_IR6 小时前
【题解】 [省选联考 2021 A/B 卷] 卡牌游戏
c++·算法
这个DBA有点耶7 小时前
COUNT慢不是因为用了*,是这5个原因——1000万行数据实测+执行计划深度解析
数据库·mysql·算法
贾伟康7 小时前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
lzx_0027 小时前
C++11(一)
开发语言·c++·算法
529宝宝起名网7 小时前
用 Python 实现名字寓意评分算法:基于 NLP 语义分析的名字内涵深度评估
python·算法·自然语言处理
带多刺的玫瑰8 小时前
Leecode#26刷题之删除有序数组中的重复项
数据结构·算法·leetcode