# 一、C++ 常用容器总览

容器 类型 底层结构 是否有序 是否去重 主要用途
vector 序列容器 动态数组 动态数组,随机访问
deque 序列容器 双端队列(分段连续) 首尾高效插入
list 序列容器 双向链表 频繁中间插入 / 删除
forward_list 序列容器 单向链表 节省内存的链表
array 序列容器 静态数组 固定大小数组
stack 容器适配器 deque (默认) 栈(LIFO)
queue 容器适配器 deque (默认) 队列(FIFO)
priority_queue 容器适配器 vector (默认) 是(堆序) 优先队列
set 关联容器 红黑树 是(升序) 有序唯一集合
multiset 关联容器 红黑树 有序可重复集合
map 关联容器 红黑树 是(按键) 有序键值对
multimap 关联容器 红黑树 有序可重复键值对
unordered_set 无序关联容器 哈希表 无序唯一集合
unordered_multiset 无序关联容器 哈希表 无序可重复集合
unordered_map 无序关联容器 哈希表 是(按键) 无序键值对
unordered_multimap 无序关联容器 哈希表 无序可重复键值对

# 二、各容器操作复杂度对比

# 1. vector<T>

  • 底层:动态数组(连续内存)
  • 特点:支持随机访问,尾部操作快,中间插入慢。
操作 复杂度 说明
push_back() 平均 O (1),最坏 O (n) 扩容时复制
pop_back() O(1)
insert(it, x) O(n) 中间插入需移动
erase(it) O(n) 删除后需移动
operator[] / at() O(1) 随机访问
size() O(1)
begin() / end() O(1)

适合:频繁随机访问、尾部增删
不适合:频繁中间插入 / 删除


# 2. deque<T> (双端队列)

  • 底层:分段连续数组(多个小数组)
  • 特点:首尾操作都快,支持随机访问。
操作 复杂度 说明
push_front() / push_back() O(1) 首尾插入都快
pop_front() / pop_back() O(1)
insert() / erase() (中间) O(n)
operator[] / at() O(1) 支持随机访问
size() O(1)

适合:需要首尾高效插入的场景(如滑动窗口)
注意:迭代器失效规则比 vector 复杂


# 3. list<T> (双向链表)

  • 底层:双向链表
  • 特点:任意位置插入 / 删除 O (1),但不支持随机访问。
操作 复杂度 说明
push_front() / push_back() O(1)
insert(it, x) O(1) 已知位置
erase(it) O(1) 已知位置
operator[] 不支持
find() O(n)
size() C++11 起 O (1),之前 O (n)

适合:频繁中间插入 / 删除
不适合:随机访问、缓存不友好


# 4. forward_list<T> (单向链表)

  • 底层:单向链表
  • 特点:比 list 更省内存,但只能单向遍历。
操作 复杂度 说明
push_front() O(1)
insert_after() O(1)
erase_after() O(1)
不支持 push_back()

适合:内存敏感、只需前向遍历的场景


# 5. array<T, N>

  • 底层:静态数组(栈上内存)
  • 特点:大小固定,性能极高。
操作 复杂度 说明
operator[] O(1)
at() O(1) 带边界检查
size() O(1)
所有操作 O(1) 固定大小

适合:小数据、固定大小、高性能场景


# 6. set<T> / map<K,V>

  • 底层红黑树(自平衡二叉搜索树)
  • 特点:自动排序、自动去重( setmap 键唯一)
操作 复杂度 说明
insert() O(log n)
find() O(log n)
erase() O(log n)
size() O(1)
遍历 O(n) 有序输出

适合:需要有序、去重、查找的场景


# 7. unordered_set<T> / unordered_map<K,V>

  • 底层哈希表(开链法或开放寻址)
  • 特点:平均极快,但无序,最坏 O (n)
操作 复杂度 说明
insert() 平均 O (1),最坏 O (n) 哈希冲突时退化
find() 平均 O (1),最坏 O (n)
erase() 平均 O (1),最坏 O (n)
size() O(1)
负载因子 影响性能 可调 max_load_factor()

适合:大数据、高频查找、不在乎顺序
不适合:需要有序输出

# 8. 容器适配器( stack , queue , priority_queue

容器 默认底层 特点 操作复杂度
stack<T> deque 后进先出(LIFO) push / pop / top : O(1)
queue<T> deque 先进先出(FIFO) push / pop / front : O(1)
priority_queue<T> vector + 堆 最大 / 最小元素在顶 push : O(log n), top : O(1), pop : O(log n)

它们不是真正容器,而是基于其他容器的封装,接口受限。

# 选择

需求 推荐容器
动态数组,随机访问 vector
首尾都能高效插入 deque
频繁中间插入 / 删除 list
固定大小数组 array
快速查找、去重(不在乎顺序) unordered_set / unordered_map
需要有序输出、去重 set / map
栈操作 stack
队列操作 queue
找最大 / 最小元素(堆) priority_queue

# 总结

口诀 对应容器
“要快用 unordered” unordered_set/map (平均 O (1))
“要序用 set/map” set/map (O (log n),有序)
“通用选 vector” vector (最常用)
“首尾快用 deque” deque (双端高效)
“中间删用 list” list (任意位置 O (1) 删除)
“最大最小用堆” priority_queue

LRU:

lru
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// 哈希表+双向链表
struct DNode;
struct DNode {
int key, value;
DNode* pre;
DNode* next;
DNode(): key(-1), value(-1), pre(nullptr), next(nullptr){}
DNode(int key, int val): key(key), value(val), pre(nullptr), next(nullptr) {}
};
class LRUCache {
public:
LRUCache(int capacity) {
this->capacity = capacity;
head = new DNode();
tail = new DNode();
head->next = tail;
tail->pre = head;
this->size = 0;
}

int get(int key) {
if(mp.find(key) != mp.end()){
DNode* pre = mp[key]->pre;
pre->next = mp[key]->next;
mp[key]->next->pre = pre;
DNode* next = head->next;
head->next = mp[key];
mp[key]->pre = head;
mp[key]->next = next;
next->pre = mp[key];
return mp[key]->value;
}else{
return -1;
}
}

void put(int key, int value) {
if(mp.find(key) != mp.end()){
mp[key]->value = value;
DNode* pre = mp[key]->pre;
pre->next = mp[key]->next;
mp[key]->next->pre = pre;
DNode* next = head->next;
head->next = mp[key];
mp[key]->pre = head;
mp[key]->next = next;
next->pre = mp[key];
}else{
if(this->size < this->capacity){
DNode* p = head->next;
DNode* newNode = new DNode(key, value);
head->next = newNode;
newNode->pre = head;
newNode->next = p;
p->pre = newNode;
mp[key] = newNode;
this->size++;
}else{
DNode* remove = tail->pre;
mp.erase(remove->key);
remove->pre->next = tail;
tail->pre = remove->pre;
delete remove;
DNode* newNode = new DNode(key, value);
DNode* nxt = head->next;
head->next = newNode;
newNode->pre = head;
newNode->next = nxt;
nxt->pre = newNode;
mp[key] = newNode;
}
}
return;
}
private:
int capacity;
int size;
unordered_map<int, DNode*> mp;
DNode* head;
DNode* tail;
};


反转链表

reverse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};

ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;

while (curr != nullptr) {
ListNode* next = curr->next; // 保存下一个节点
curr->next = prev; // 反转当前节点
prev = curr; // prev 前进
curr = next; // curr 前进
}

return prev; // 新的头节点
}
Edited on

Give me a cup of [coffee]~( ̄▽ ̄)~*

NoResponse WeChat Pay

WeChat Pay

NoResponse Alipay

Alipay

NoResponse PayPal

PayPal