代码链接:https://gitee.com/hu_yuchen/code/tree/master/C+±Review/4.STL
STL(标准模板库)容器是 C++ 标准库的核心组件,用于高效存储和操作数据。它们分为以下几类:
每个容器针对特定场景优化,底层实现结合了经典数据结构(如数组、链表、红黑树、哈希表)和高效算法。选择合适的容器能显著提升程序性能。以下逐一分析每个容器的结构、实现、使用方法及扩充知识点,并通过详细代码示例展示其功能。
1. 是什么结构,底层是什么?
begin
(起始)、end
(最后一个元素的下一位置)、end_of_storage
(分配内存的末尾)。size
达到 capacity
时,vector 分配一块更大的内存(通常为当前容量的 2 倍),将原有元素复制或移动到新内存,释放旧内存。扩容导致迭代器失效。std::allocator
。2. 如何使用,支持哪些使用方法?
vector v;
vector v(n);
(默认值初始化)vector v(n, val);
vector v = {1, 2, 3};
vector v(other.begin(), other.end());
vector v2(v1);
vector v2(std::move(v1));
v[i]
:下标访问,无边界检查。v.at(i)
:带边界检查,抛出 std::out_of_range
。front()
/back()
:访问首/尾元素。data()
:返回底层数组指针。push_back(val)
:尾部添加。emplace_back(args...)
:尾部构造(更高效)。insert(pos, val)
:指定位置插入。insert(pos, n, val)
:插入 n 个值。insert(pos, first, last)
:插入范围。pop_back()
:删除尾部。erase(pos)
:删除指定位置。erase(first, last)
:删除范围。clear()
:清空所有元素。size()
:元素数量。capacity()
:当前容量。empty()
:是否为空。resize(n)
:调整大小,填充默认值或截断。resize(n, val)
:调整大小,填充指定值。reserve(n)
:预分配容量。shrink_to_fit()
:释放多余容量(C++11)。begin()
/end()
:正向迭代器。rbegin()
/rend()
:反向迭代器。cbegin()
/cend()
:常量迭代器(C++11)。swap(v2)
:交换两个 vector。assign(n, val)
:重新赋值 n 个值。assign(first, last)
:重新赋值范围。代码示例(扩充):
#include
#include
using namespace std;
int main() {
// 多种构造
vector<int> v1; // 默认
vector<int> v2(3, 10); // 3 个 10
vector<int> v3 = {1, 2, 3}; // 初始列表
vector<int> v4(v3.begin(), v3.end()); // 范围构造
vector<int> v5(v3); // 拷贝构造
// 添加元素
v1.push_back(1); // 1
v1.emplace_back(2); // 1, 2
v1.insert(v1.begin(), 0); // 0, 1, 2
v1.insert(v1.end(), 2, 3); // 0, 1, 2, 3, 3
// 访问
cout << "v1[0]: " << v1[0] << endl; // 0
cout << "front: " << v1.front() << ", back: " << v1.back() << endl; // 0, 3
// 遍历
cout << "v1: ";
for (auto it = v1.cbegin(); it != v1.cend(); ++it) {
cout << *it << " "; // 0 1 2 3 3
}
cout << endl;
// 删除
v1.erase(v1.begin() + 1); // 删除 1
v1.erase(v1.begin(), v1.begin() + 2); // 删除 0, 2
cout << "After erase: ";
for (int x : v1) {
cout << x << " "; // 3 3
}
cout << endl;
// 大小与容量
v1.reserve(100); // 预分配
cout << "Size: " << v1.size() << ", Capacity: " << v1.capacity() << endl;
v1.shrink_to_fit(); // 释放多余容量
cout << "After shrink, Capacity: " << v1.capacity() << endl;
// 交换
vector<int> v6 = {4, 5};
v1.swap(v6);
cout << "v1 after swap: ";
for (int x : v1) {
cout << x << " "; // 4 5
}
cout << endl;
return 0;
}
理解与扩充:
reserve
预分配容量可避免频繁扩容;emplace_back
比 push_back
更高效(避免拷贝)。1. 是什么结构,底层是什么?
2. 如何使用,支持哪些使用方法?
list lst;
list lst(n);
list lst(n, val);
list lst = {1, 2, 3};
list lst(other.begin(), other.end());
list lst2(lst1);
, list lst2(std::move(lst1));
push_front(val)
/push_back(val)
:头部/尾部添加。emplace_front(args...)
/emplace_back(args...)
:头部/尾部构造。insert(pos, val)
:指定位置插入。insert(pos, n, val)
:插入 n 个值。insert(pos, first, last)
:插入范围。pop_front()
/pop_back()
:删除头部/尾部。erase(pos)
:删除指定位置。erase(first, last)
:删除范围。clear()
:清空。remove(val)
:删除所有等于 val 的元素。remove_if(pred)
:删除满足谓词的元素。size()
:元素数量(C++11 前可能 O(n))。empty()
:是否为空。splice(pos, other)
:将 other 整个链表拼接。splice(pos, other, it)
:拼接 other 的单个元素。splice(pos, other, first, last)
:拼接 other 的范围。sort()
:排序(默认升序)。sort(comp)
:自定义比较器排序。merge(other)
:合并有序链表。unique()
:删除连续重复元素。reverse()
:反转链表。begin()
/end()
:双向迭代器。rbegin()
/rend()
:反向迭代器。代码示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
list<int> lst = {3, 2, 1};
list<int> lst2(2, 5); // 5, 5
// 添加
lst.push_front(0); // 0, 3, 2, 1
lst.emplace_back(4); // 0, 3, 2, 1, 4
lst.insert(++lst.begin(), 10); // 0, 10, 3, 2, 1, 4
// 遍历
cout << "lst: ";
for (auto x : lst) {
cout << x << " "; // 0 10 3 2 1 4
}
cout << endl;
// 删除
lst.pop_front(); // 10, 3, 2, 1, 4
lst.remove(2); // 删除所有 2
cout << "After remove 2: ";
for (auto x : lst) {
cout << x << " "; // 10 3 1 4
}
cout << endl;
// 排序
lst.sort(); // 1, 3, 4, 10
cout << "Sorted: ";
for (auto x : lst) {
cout << x << " "; // 1 3 4 10
}
cout << endl;
// 拼接
lst.splice(lst.begin(), lst2); // 将 lst2 拼接至 lst 开头
cout << "After splice: ";
for (auto x : lst) {
cout << x << " "; // 5 5 1 3 4 10
}
cout << endl;
// 去重
lst.sort();
lst.unique(); // 删除连续重复元素
cout << "After unique: ";
for (auto x : lst) {
cout << x << " "; // 1 3 4 5 10
}
cout << endl;
return 0;
}
理解与扩充:
splice
和 merge
是 list 的高效操作,复杂度 O(1) 或 O(n),适合链表合并。size()
在 C++98 中可能 O(n),C++11 后优化为 O(1)。1. 是什么结构,底层是什么?
deque
,可指定 vector
或 list
。push
, pop
, top
)。deque
:默认,高效尾部操作,内存分块存储。vector
:连续存储,扩容可能影响性能。list
:适合动态调整,但内存开销大。2. 如何使用,支持哪些使用方法?
stack s;
stack> s;
stack s2(s1);
stack s2(std::move(s1));
push(val)
:入栈。emplace(args...)
:构造入栈。pop()
:出栈(无返回值)。top()
:访问栈顶。size()
:元素数量。empty()
:是否为空。swap(s2)
:交换两个 stack。代码示例(扩充):
#include
#include
#include
using namespace std;
int main() {
// 构造
stack<int> s; // 默认 deque
stack<int, vector<int>> s_vec; // 使用 vector
// 入栈
s.push(1);
s.push(2);
s.emplace(3); // 构造入栈
// 访问
cout << "Top: " << s.top() << endl; // 3
// 出栈
s.pop();
cout << "Top after pop: " << s.top() << endl; // 2
// 大小
cout << "Size: " << s.size() << endl; // 2
// 交换
stack<int> s2;
s2.push(4);
s.swap(s2);
cout << "s top after swap: " << s.top() << endl; // 4
cout << "s2 top: " << s2.top() << endl; // 2
return 0;
}
理解与扩充:
emplace
避免拷贝;选择合适的底层容器(如 vector 节省空间)。Container
适配底层容器,接口简洁但功能有限。1. 是什么结构,底层是什么?
deque
,可指定 list
。push
, pop
, front
, back
)。deque
:高效首尾操作,分块存储。list
:适合动态调整,但内存开销大。std::deque
提供双端队列功能,queue 是其子集。2. 如何使用,支持哪些使用方法?
queue q;
queue> q;
queue q2(q1);
, queue q2(std::move(q1));
push(val)
:入队。emplace(args...)
:构造入队。pop()
:出队。front()
:访问队首。back()
:访问队尾。size()
:元素数量。empty()
:是否为空。swap(q2)
:交换两个 queue。代码示例(扩充):
#include
#include
#include
using namespace std;
int main() {
// 构造
queue<int> q; // 默认 deque
queue<int, list<int>> q_list; // 使用 list
// 入队
q.push(1);
q.push(2);
q.emplace(3);
// 访问
cout << "Front: " << q.front() << endl; // 1
cout << "Back: " << q.back() << endl; // 3
// 出队
q.pop();
cout << "Front after pop: " << q.front() << endl; // 2
// 大小
cout << "Size: " << q.size() << endl; // 2
// 交换
queue<int> q2;
q2.push(4);
q.swap(q2);
cout << "q front after swap: " << q.front() << endl; // 4
cout << "q2 front: " << q2.front() << endl; // 2
return 0;
}
理解与扩充:
emplace
避免拷贝;deque
作为默认容器平衡了性能和内存。deque
接口实现 FIFO,简洁但功能有限。1. 是什么结构,底层是什么?
vector
存储。std::make_heap
, std::push_heap
, std::pop_heap
维护堆性质。std::less
(最大堆),可指定 std::greater
(最小堆)。vector
中,父子节点通过索引计算(父:i/2
,子:2i, 2i+1
)。vector
的分配器。2. 如何使用,支持哪些使用方法?
priority_queue pq;
priority_queue, greater> pq;
priority_queue pq(v.begin(), v.end());
priority_queue, MyComp> pq;
push(val)
:入队。emplace(args...)
:构造入队。pop()
:出队。top()
:访问队首。size()
:元素数量。empty()
:是否为空。swap(pq2)
:交换两个 priority_queue。代码示例(扩充):
#include
#include
#include
using namespace std;
int main() {
// 最大堆
priority_queue<int> pq;
pq.push(3);
pq.push(1);
pq.emplace(4);
cout << "Top: " << pq.top() << endl; // 4
pq.pop();
cout << "Top after pop: " << pq.top() << endl; // 3
// 最小堆
priority_queue<int, vector<int>, greater<int>> min_pq({3, 1, 4});
cout << "Min Top: " << min_pq.top() << endl; // 1
// 自定义比较器
struct MyComp {
bool operator()(int a, int b) { return a > b; } // 最小堆
};
priority_queue<int, vector<int>, MyComp> custom_pq;
custom_pq.push(3);
custom_pq.push(1);
custom_pq.push(4);
cout << "Custom Top: " << custom_pq.top() << endl; // 1
return 0;
}
理解与扩充:
emplace
避免拷贝;初始范围构造可减少插入次数。vector
实现,调整算法确保堆性质;比较器决定优先级。1. 是什么结构,底层是什么?
pair
)。std::less
(升序),可自定义。const Key
)。2. 如何使用,支持哪些使用方法?
map m;
map m = {{"a", 1}, {"b", 2}};
map m(other.begin(), other.end());
map m2(m1);
, map m2(std::move(m1));
map> m;
(降序)。m[key] = val
:插入或更新。insert(pair)
:插入键值对。insert(pos, pair)
:带提示位置插入(优化性能)。insert(first, last)
:插入范围。emplace(args...)
:构造插入。insert_or_assign(key, val)
(C++17):插入或覆盖。find(key)
:返回迭代器。count(key)
:返回键出现次数(0 或 1)。at(key)
:带边界检查访问,抛出 std::out_of_range
。lower_bound(key)
/upper_bound(key)
:查找键的范围。erase(key)
:删除指定键。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。clear()
:清空。size()
:元素数量。empty()
:是否为空。max_size()
:最大可能元素数。swap(m2)
:交换两个 map。key_comp()
/value_comp()
:返回比较器。代码示例(扩充):
#include
#include
#include
using namespace std;
int main() {
// 构造
map<string, int> m = {{"apple", 5}, {"banana", 3}};
map<string, int, greater<string>> m_desc; // 降序
// 插入
m["orange"] = 2;
m.insert({"grape", 4});
m.emplace("pear", 1);
m.insert_or_assign("apple", 6); // 覆盖 apple
// 遍历
cout << "m: ";
for (const auto& p : m) {
cout << p.first << ":" << p.second << " "; // apple:6 banana:3 grape:4 orange:2 pear:1
}
cout << endl;
// 查找
auto it = m.find("banana");
if (it != m.end()) {
cout << "Found banana: " << it->second << endl; // 3
}
cout << "apple count: " << m.count("apple") << endl; // 1
// 范围查找
auto lb = m.lower_bound("b");
auto ub = m.upper_bound("c");
cout << "Keys [b, c): ";
for (auto it = lb; it != ub; ++it) {
cout << it->first << ":" << it->second << " "; // banana:3
}
cout << endl;
// 删除
m.erase("banana");
m.erase(m.find("grape"), m.end()); // 删除 grape 及之后
cout << "After erase: ";
for (const auto& p : m) {
cout << p.first << ":" << p.second << " "; // apple:6
}
cout << endl;
return 0;
}
理解与扩充:
insert(pos, pair)
可利用红黑树局部性;emplace
避免拷贝。1. 是什么结构,底层是什么?
std::less
,可自定义。const T
)。2. 如何使用,支持哪些使用方法?
set s;
set s = {1, 2, 3};
set s(v.begin(), v.end());
set> s;
(降序)。insert(val)
:插入元素。insert(pos, val)
:带提示位置插入。insert(first, last)
:插入范围。emplace(args...)
:构造插入。find(val)
:返回迭代器。count(val)
:返回元素出现次数(0 或 1)。lower_bound(val)
/upper_bound(val)
:查找范围。erase(val)
:删除指定值。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。size()
:元素数量。empty()
:是否为空。swap(s2)
:交换两个 set。key_comp()
:返回比较器。code 示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
set<int> s = {3, 1, 3}; // 自动去重
set<int, greater<int>> s_desc; // 降序
// 插入
s.insert(2);
s.emplace(4);
cout << "s: ";
for (auto x : s) {
cout << x << " "; // 1 2 3 4
}
cout << endl;
// 查找
if (s.find(2) != s.end()) {
cout << "Found 2" << endl;
}
cout << "Count of 3: " << s.count(3) << endl; // 1
// 范围查找
auto lb = s.lower_bound(2);
auto ub = s.upper_bound(3);
cout << "Elements [2, 3]: ";
for (auto it = lb; it != ub; ++it) {
cout << *it << " "; // 2 3
}
cout << endl;
// 删除
s.erase(1);
s.erase(s.find(2), s.end()); // 删除 2 及之后
cout << "After erase: ";
for (auto x : s) {
cout << x << " "; // 3
}
cout << endl;
return 0;
}
理解与扩充:
insert(pos, val)
利用红黑树局部性;emplace
避免拷贝。1. 是什么结构,底层是什么?
std::less
。2. 如何使用,支持哪些使用方法?
multiset ms;
multiset ms = {1, 1, 2};
multiset ms(v.begin(), v.end());
multiset> ms;
insert(val)
:插入元素。insert(pos, val)
:带提示位置插入。insert(first, last)
:插入范围。emplace(args...)
:构造插入。find(val)
:返回第一个匹配的迭代器。count(val)
:返回元素出现次数。equal_range(val)
:返回元素范围。lower_bound(val)
/upper_bound(val)
:查找范围。erase(val)
:删除所有等于 val 的元素。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。size()
:元素数量。empty()
:是否为空。code 示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
multiset<int> ms = {1, 1, 2};
// 插入
ms.insert(2);
ms.emplace(3);
cout << "ms: ";
for (auto x : ms) {
cout << x << " "; // 1 1 2 2 3
}
cout << endl;
// 查找
cout << "Count of 1: " << ms.count(1) << endl; // 2
auto range = ms.equal_range(2);
cout << "Elements == 2: ";
for (auto it = range.first; it != range.second; ++it) {
cout << *it << " "; // 2 2
}
cout << endl;
// 删除
ms.erase(ms.find(1)); // 删除一个 1
ms.erase(2); // 删除所有 2
cout << "After erase: ";
for (auto x : ms) {
cout << x << " "; // 1 3
}
cout << endl;
return 0;
}
理解与扩充:
equal_range
高效查找重复元素;emplace
避免拷贝。1. 是什么结构,底层是什么?
std::less
。2. 如何使用,支持哪些使用方法?
multimap mm;
multimap mm = {{"a", 1}, {"a", 2}};
multimap mm(m.begin(), m.end());
multimap> mm;
insert(pair)
:插入键值对。insert(pos, pair)
:带提示位置插入。insert(first, last)
:插入范围。emplace(args...)
:构造插入。find(key)
:返回第一个匹配的迭代器。count(key)
:返回键出现次数。equal_range(key)
:返回键的范围。lower_bound(key)
/upper_bound(key)
:查找范围。erase(key)
:删除所有等于 key 的键值对。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。size()
:元素数量。empty()
:是否为空。code 示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
multimap<string, int> mm = {{"apple", 1}, {"apple", 2}};
// 插入
mm.insert({"banana", 3});
mm.emplace("apple", 4);
cout << "mm: ";
for (const auto& p : mm) {
cout << p.first << ":" << p.second << " "; // apple:1 apple:2 apple:4 banana:3
}
cout << endl;
// 查找
cout << "Count of apple: " << mm.count("apple") << endl; // 3
auto range = mm.equal_range("apple");
cout << "Values for apple: ";
for (auto it = range.first; it != range.second; ++it) {
cout << it->second << " "; // 1 2 4
}
cout << endl;
// 删除
mm.erase("apple"); // 删除所有 apple
cout << "After erase: ";
for (const auto& p : mm) {
cout << p.first << ":" << p.second << " "; // banana:3
}
cout << endl;
return 0;
}
理解与扩充:
equal_range
高效查找重复键;emplace
避免拷贝。1. 是什么结构,底层是什么?
std::hash
,可自定义。2. 如何使用,支持哪些使用方法?
unordered_set us;
unordered_set us = {1, 2, 3};
unordered_set us(v.begin(), v.end());
unordered_set us;
insert(val)
:插入元素。insert(first, last)
:插入范围。emplace(args...)
:构造插入。find(val)
:返回迭代器。count(val)
:返回元素出现次数(0 或 1)。erase(val)
:删除指定值。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。size()
:元素数量。empty()
:是否为空。bucket_count()
:桶数量。load_factor()
:当前负载因子。max_load_factor(f)
:设置最大负载因子。rehash(n)
:重新设置桶数。reserve(n)
:预分配空间。code 示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
unordered_set<int> us = {1, 2, 3, 2};
// 插入
us.insert(4);
us.emplace(5);
cout << "us: ";
for (auto x : us) {
cout << x << " "; // 无序,如 1 2 3 4 5
}
cout << endl;
// 查找
if (us.find(2) != us.end()) {
cout << "Found 2" << endl;
}
cout << "Count of 3: " << us.count(3) << endl; // 1
// 删除
us.erase(1);
cout << "After erase: ";
for (auto x : us) {
cout << x << " "; // 2 3 4 5
}
cout << endl;
// 哈希管理
cout << "Bucket count: " << us.bucket_count() << endl;
us.max_load_factor(0.5); // 降低负载因子
us.rehash(20); // 设置桶数
cout << "New bucket count: " << us.bucket_count() << endl;
return 0;
}
理解与扩充:
reserve
预分配桶数减少重哈希;自定义哈希函数提高分布均匀性。1. 是什么结构,底层是什么?
std::hash
,可自定义。2. 如何使用,支持哪些使用方法?
unordered_map um;
unordered_map um = {{"a", 1}, {"b", 2}};
unordered_map um(m.begin(), m.end());
unordered_map um;
um[key] = val
:插入或更新。insert(pair)
:插入键值对。insert(first, last)
:插入范围。emplace(args...)
:构造插入。insert_or_assign(key, val)
(C++17):插入或覆盖。find(key)
:返回迭代器。count(key)
:返回键出现次数(0 或 1)。at(key)
:带边界检查访问。erase(key)
:删除指定键。erase(pos)
:删除迭代器位置。erase(first, last)
:删除范围。size()
:元素数量。empty()
:是否为空。bucket_count()
:桶数量。load_factor()
:负载因子。max_load_factor(f)
:设置最大负载因子。rehash(n)
:重新设置桶数。reserve(n)
:预分配空间。code 示例(扩充):
#include
#include
using namespace std;
int main() {
// 构造
unordered_map<string, int> um = {{"apple", 5}, {"banana", 3}};
// 插入
um["orange"] = 2;
um.insert({"grape", 4});
um.emplace("pear", 1);
um.insert_or_assign("apple", 6);
// 遍历
cout << "um: ";
for (const auto& p : um) {
cout << p.first << ":" << p.second << " "; // 无序
}
cout << endl;
// 查找
if (um.find("apple") != um.end()) {
cout << "Found apple: " << um.at("apple") << endl; // 6
}
cout << "Count of banana: " << um.count("banana") << endl; // 1
// 删除
um.erase("banana");
cout << "After erase: ";
for (const auto& p : um) {
cout << p.first << ":" << p.second << " ";
}
cout << endl;
// 哈希管理
cout << "Bucket count: " << um.bucket_count() << endl;
um.reserve(100); // 预分配
cout << "New bucket count: " << um.bucket_count() << endl;
return 0;
}
理解与扩充:
reserve
减少重哈希;emplace
避免拷贝。STL 容器提供了多样化的数据管理工具,针对不同场景优化:
选择建议:
随机访问:vector(O(1) 访问)优于 deque(分块存储)。
频繁插入/删除:list(O(1) 操作,迭代器稳定)优于 vector。
有序键值:map(红黑树,O(log n))优于 unordered_map(无序)。
高效查找:unordered_map/unordered_set(O(1) 平均)优于 map/set。
优先级:priority_queue(堆,O(log n) 调整)优于手动维护。
简单栈/队列:stack/queue 提供简洁接口,优于直接使用 vector/list。
内存优化:使用 reserve
(vector, unordered_ 容器)或自定义分配器。
性能分析:根据数据量和操作频率选择容器,如小数据量可用 vector,频繁查找用 unordered_map。
算法结合:STL 算法(如 std::sort
, std::find
)与容器结合,提升效率。
线程安全:STL 容器非线程安全,多线程场景需加锁或使用并发容器。