C++学习系列(10):STL 容器底层原理
1. 引言
STL(Standard Template Library,标准模板库) 是 C++ 最重要的组成部分之一,其中 容器(Container) 提供了丰富的数据结构支持,如 vector
、list
、map
、set
等。
本篇博客将介绍:
- STL 容器的基本概念
- 不同 STL 容器的底层实现
- STL 容器的性能对比
- 常见的 STL 容器使用技巧
2. STL 容器概览
STL 容器可分为以下几类:
容器类型 | 示例 | 底层结构 | 特点 |
---|---|---|---|
顺序容器 | vector 、deque 、list | 动态数组 / 双向链表 | 适用于存储有序数据 |
关联容器 | map 、set 、multimap | 红黑树(RB-Tree) | 适用于快速查找和排序 |
无序容器 | unordered_map 、unordered_set | 哈希表(Hash Table) | 适用于快速查找,但无序 |
3. vector
底层实现
3.1 vector
的基本特性
✅ 动态数组:内存连续,支持随机访问
✅ 自动扩容:超过容量时,vector
会 重新分配更大的内存,并拷贝数据
✅ 扩容倍数:通常是 1.5 - 2 倍
3.2 vector
的底层结构
template <typename T>
class vector {
private:
T* data; // 指向存储数组
size_t size; // 当前元素个数
size_t capacity; // 总容量
public:
void push_back(const T& value); // 添加元素
void pop_back(); // 删除最后一个元素
T& operator[](size_t index); // 访问元素
};
3.3 vector
的自动扩容
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec;
for (int i = 0; i < 10; ++i) {
vec.push_back(i);
std::cout << "Size: " << vec.size() << ", Capacity: " << vec.capacity() << std::endl;
}
return 0;
}
📌 解析
size()
返回当前元素个数capacity()
返回当前分配的空间
4. list
底层实现
4.1 list
的基本特性
✅ 双向链表:每个节点存储 前后指针
✅ 插入、删除高效:O(1)
复杂度,但 不支持随机访问
4.2 list
的底层结构
template <typename T>
class ListNode {
public:
T value;
ListNode* prev;
ListNode* next;
};
4.3 list
的插入删除
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {1, 2, 3};
lst.push_front(0);
lst.push_back(4);
for (int x : lst) {
std::cout << x << " ";
}
return 0;
}
📌 解析
push_front()
插入头部push_back()
插入尾部list
不支持 随机访问(operator[]
)
5. map
和 set
(红黑树)
5.1 map
和 set
的底层实现
✅ 红黑树(RB-Tree) 作为底层数据结构
✅ 自动排序,插入数据时 按键值排序
✅ 查找复杂度 O(log N)
5.2 map
的基本操作
#include <iostream>
#include <map>
int main() {
std::map<int, std::string> mp;
mp[1] = "Apple";
mp[2] = "Banana";
for (const auto& [key, value] : mp) {
std::cout << key << ": " << value << std::endl;
}
return 0;
}
📌 解析
map
自动按 key 排序,不需要手动排序
6. unordered_map
(哈希表)
6.1 unordered_map
的底层实现
✅ 哈希表(Hash Table)
✅ 查找效率 O(1)
,比 map
快
✅ 无序存储
6.2 unordered_map
的使用
#include <iostream>
#include <unordered_map>
int main() {
std::unordered_map<std::string, int> umap;
umap["apple"] = 5;
umap["banana"] = 10;
for (const auto& [key, value] : umap) {
std::cout << key << ": " << value << std::endl;
}
return 0;
}
📌 适用于
- 需要 快速查找
- 对数据 顺序没有要求
7. STL 容器性能对比
容器 | 结构 | 插入性能 | 访问性能 | 适用场景 |
---|---|---|---|---|
vector | 动态数组 | O(1) (尾部插入) | O(1) (随机访问) | 适用于 大量读写,不频繁插入 |
list | 双向链表 | O(1) (头尾插入) | O(n) (遍历) | 适用于 频繁插入删除 |
map | 红黑树 | O(log N) | O(log N) | 有序存储,快速查找 |
unordered_map | 哈希表 | O(1) | O(1) | 最快的查找方式,无序存储 |
8. 总结
✅ vector
适用于 随机访问,但 插入删除慢
✅ list
适用于 频繁插入删除,但 访问慢
✅ map
适用于 有序存储,查找 O(log N)
✅ unordered_map
适用于 无序存储,查找 O(1)
下一篇 C++学习系列(11),我们将探讨 C++ 智能指针 unique_ptr
、shared_ptr
和 weak_ptr
,敬请期待!🚀
💡 如果你喜欢这篇文章,欢迎点赞、收藏,并关注本系列!