表格汇总:
容器 | 存储结构 | 随机访问性能 | 中间插入/删除性能 | 两端插入/删除性能 | 内存管理特点 | 迭代器类型 | 适用场景 |
---|---|---|---|---|---|---|---|
vector |
动态数组 | O ( 1 ) O(1) O(1) | O ( n ) O(n) O(n) | 尾部 O ( 1 ) O(1) O(1),其他位置 O ( n ) O(n) O(n) | 当元素数量超过当前容量时,会重新分配内存并复制元素 | 随机访问迭代器 | 适合需要频繁随机访问 元素,且主要在尾部 进行插入和删除操作,元素数量可变的场景,例如存储一系列数据,需要对元素进行排序和查找操作 |
deque |
双端队列 | O ( 1 ) O(1) O(1) | O ( n ) O(n) O(n) | 头部和尾部 O ( 1 ) O(1) O(1) | 可以在两端高效地添加或删除元素,内存分配较为复杂,可能包含多个块 | 随机访问迭代器 | 适合需要在两端 频繁进行插入和删除操作,同时也需要随机访问 元素的场景,例如实现一个双端队列,或者在队列两端进行元素的快速添加和移除 |
list |
双向链表 | O ( n ) O(n) O(n) | O ( 1 ) O(1) O(1) | O ( 1 ) O(1) O(1) | 内存分配较为分散,每个元素包含数据和前后指针,动态分配内存 | 双向迭代器 | 适合需要频繁在任意位置插入和删除 元素,但不需要随机访问 的场景,例如实现一个链表数据结构,进行插入和删除操作频繁的列表操作 |
forward_list |
单向链表 | O ( n ) O(n) O(n) | O ( 1 ) O(1) O(1) | 头部 O ( 1 ) O(1) O(1),其他位置需要遍历链表 | 内存分配分散,每个元素包含数据和指向下一个元素的指针,动态分配内存 | 单向迭代器 | 适合需要频繁在头部或链表中间位置插入和删除 元素,但不需要随机访问 ,且对空间要求较为严格的场景,例如实现一个简单的单向链表,减少空间开销 |
array |
固定大小数组 | O ( 1 ) O(1) O(1) | 不支持 | 不支持 | 静态存储,大小固定,内存是连续的 | 随机访问迭代器 | 适合元素数量固定 ,需要快速随机访问 元素,且对性能要求较高 ,不允许元素数量变化的场景,例如存储一组固定大小的数组元素,已知元素数量的数组操作 |
string |
类似于动态数组,存储字符元素 | O ( 1 ) O(1) O(1) | O ( n ) O(n) O(n) | 尾部 O ( 1 ) O(1) O(1),其他位置 O ( n ) O(n) O(n) | 当元素数量超过当前容量时,会重新分配内存并复制元素 | 随机访问迭代器 | 专门用于存储字符序列 ,适合对字符串进行操作,如存储文本信息,对字符串进行拼接、查找、截取等操作 |
map |
红黑树 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) | 不支持 | 节点存储元素,根据键的顺序动态分配内存,内存分配可能会比较频繁,以保证树的平衡 | 双向迭代器 | 适合需要根据键快速查找、插入和删除 元素,且键唯一 ,元素按关键字有序存储 ,需要按序遍历元素的场景,例如存储键值对,根据键查找相应的值,且键有序 |
set |
红黑树 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) | 不支持 | 节点存储元素,根据键的顺序动态分配内存,内存分配可能会比较频繁,以保证树的平衡 | 双向迭代器 | 适合存储唯一的关键字 集合,需要按关键字有序存储 和快速查找元素,例如存储一组不重复的关键字,对关键字进行有序遍历 |
multimap |
红黑树 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) | 不支持 | 节点存储元素,根据键的顺序动态分配内存,内存分配可能会比较频繁,以保证树的平衡 | 双向迭代器 | 适合存储键值对,允许键重复 ,需要根据键查找元素,且元素按关键字有序存储,需要按序遍历元素的场景,例如存储多个具有相同关键字的键值对,进行有序存储和查找 |
multiset |
红黑树 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) | 不支持 | 节点存储元素,根据键的顺序动态分配内存,内存分配可能会比较频繁,以保证树的平衡 | 双向迭代器 | 适合存储允许重复 的关键字集合,需要按关键字有序存储和快速查找元素,例如存储一组允许重复的关键字,对关键字进行有序遍历 |
unordered_map |
哈希表 | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | 不支持 | 基于哈希表存储元素,使用桶存储,内存分配可能会根据元素的哈希值分散在不同位置 | 前向迭代器 | 适合需要根据键快速查找、插入和删除 元素,不要求元素有序 存储,允许键唯一 的场景,例如快速查找键值对,对性能要求高,不需要元素有序 |
unordered_set |
哈希表 | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | 不支持 | 基于哈希表存储元素,使用桶存储,内存分配可能会根据元素的哈希值分散在不同位置 | 前向迭代器 | 适合存储唯一的关键字 集合,不要求元素有序 存储,需要快速查找元素的场景,例如存储一组不重复的关键字,快速查找关键字是否存在 |
unordered_multimap |
哈希表 | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | 不支持 | 基于哈希表存储元素,使用桶存储,内存分配可能会根据元素的哈希值分散在不同位置 | 前向迭代器 | 适合存储键值对 ,允许键重复 ,不要求元素有序 存储,需要快速查找元素的场景,例如存储多个具有相同关键字的键值对,快速查找具有某个关键字的键值对 |
unordered_multiset |
哈希表 | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | O ( 1 ) O(1) O(1)(平均), O ( n ) O(n) O(n)(最坏) | 不支持 | 基于哈希表存储元素,使用桶存储,内存分配可能会根据元素的哈希值分散在不同位置 | 前向迭代器 | 适合存储允许重复的关键字 集合,不要求元素有序 存储,需要快速查找元素的场景,例如存储一组允许重复的关键字,快速查找关键字是否存在 |
详细介绍:
以下是对 C++ 中各个容器按照存储结构、随机访问性能、中间插入/删除性能、两端插入/删除性能、内存管理特点、迭代器类型和适用场景的详细介绍:
一、顺序容器
vector:
- 存储结构:基于动态数组实现。当创建
vector
时,它会分配一块连续的内存空间,元素存储在这块内存中。 - 随机访问性能:由于是连续存储,可以通过指针运算快速定位元素,时间复杂度为 O ( 1 ) O(1) O(1)。例如,使用
vector[i]
可以直接访问第i
个元素。 - 中间插入/删除性能:在中间或头部插入/删除元素时,需要将插入/删除点之后的元素依次向后/向前移动,以保持元素的连续性,时间复杂度为 O ( n ) O(n) O(n)。例如,使用
vector.insert(vector.begin() + i, value)
在位置i
插入元素时,从i
开始的元素都需要移动。 - 两端插入/删除性能:在尾部插入元素,通常在有足够空间时时间复杂度为 O ( 1 ) O(1) O(1),但如果空间不足需要重新分配和复制元素,时间复杂度为 O ( n ) O(n) O(n);在尾部删除元素时间复杂度为 O ( 1 ) O(1) O(1)。例如,使用
vector.push_back(value)
或vector.pop_back()
。 - 内存管理特点:当添加元素超过当前容量时,会重新分配一个更大的连续内存空间(通常是当前容量的两倍),并将旧元素复制到新空间中。这可能导致性能开销,尤其是对于大型
vector
。 - 迭代器类型:随机访问迭代器,可以像指针一样进行加减操作,支持随机访问元素。
- 适用场景:适用于需要频繁访问元素,且元素数量会动态变化,但主要在尾部进行插入和删除操作的场景。例如存储一系列数据并对其进行排序、查找或遍历操作。
- 存储结构:基于动态数组实现。当创建
deque:
- 存储结构:双端队列通常由多个块组成,每个块存储多个元素,使用指针数组来管理这些块,元素在块内连续存储。
- 随机访问性能:支持快速随机访问,时间复杂度为 O ( 1 ) O(1) O(1)。可以使用
deque[i]
来访问元素。 - 中间插入/删除性能:类似于
vector
,在中间插入/删除元素需要移动元素,时间复杂度为 O ( n ) O(n) O(n)。 - 两端插入/删除性能:在头部和尾部插入/删除元素的速度很快,时间复杂度为 O ( 1 ) O(1) O(1)。可以使用
deque.push_front(value)
、deque.pop_front()
、deque.push_back(value)
和deque.pop_back()
。 - 内存管理特点:能够在两端高效扩展,内存分配比
vector
更灵活,不会像vector
那样需要复制整个数组,而是在头部或尾部添加新的块。 - 迭代器类型:随机访问迭代器。
- 适用场景:需要在队列两端快速插入和删除元素,同时又需要随机访问元素的场景,例如实现一个双端队列或滑动窗口。
list:
- 存储结构:双向链表,每个元素包含数据以及指向前一个和后一个元素的指针,元素在内存中不连续。
- 随机访问性能:由于元素不连续,要访问第
i
个元素,需要从头或尾开始遍历,时间复杂度为 O ( n ) O(n) O(n)。例如,使用迭代器遍历列表直到找到所需元素。 - 中间插入/删除性能:在任意位置插入/删除元素只需要修改前后元素的指针,时间复杂度为 O ( 1 ) O(1) O(1)。例如,使用
list.insert(it, value)
在迭代器it
处插入元素。 - 两端插入/删除性能:在头部或尾部插入/删除元素,只需修改相应的指针,时间复杂度为 O ( 1 ) O(1) O(1) 。可以使用
list.push_front(value)
、list.pop_front()
、list.push_back(value)
和list.pop_back()
。 - 内存管理特点:每个元素单独分配内存,内存使用较为灵活,但会有额外的指针开销。
- 迭代器类型:双向迭代器,可以向前或向后移动,但不支持随机访问。
- 适用场景:适用于需要频繁在任意位置插入和删除元素,但不需要快速随机访问的场景,如实现链表数据结构,用于频繁插入和删除操作的列表操作。
forward_list:
- 存储结构:单向链表,每个元素包含数据和指向下一个元素的指针,元素在内存中不连续。
- 随机访问性能:与
list
类似,需要从头开始遍历,时间复杂度为 O ( n ) O(n) O(n)。 - 中间插入/删除性能:在任意位置插入/删除元素只需要修改指针,时间复杂度为 O ( 1 ) O(1) O(1)。但由于是单向链表,插入/删除操作需要在元素之前的位置操作,例如,使用
forward_list.insert_after(it, value)
在迭代器it
之后插入元素。 - 两端插入/删除性能:在头部插入/删除元素很方便,时间复杂度为 O ( 1 ) O(1) O(1),在尾部插入/删除元素需要遍历整个链表,时间复杂度为 O ( n ) O(n) O(n)。可以使用
forward_list.push_front(value)
和forward_list.pop_front()
。 - 内存管理特点:每个元素单独分配内存,比
list
更节省空间,因为只有一个指针。 - 迭代器类型:单向迭代器,只能向后移动。
- 适用场景:适用于需要频繁在头部或链表中间位置插入和删除元素,且对空间要求严格,不需要随机访问的场景,例如实现一个简单的单向链表,减少空间开销。
array:
- 存储结构:固定大小的数组,元素存储在连续的内存空间中,大小在编译时确定。
- 随机访问性能:支持快速随机访问,时间复杂度为 O ( 1 ) O(1) O(1)。可以使用
array[i]
访问元素。 - 中间插入/删除性能:不支持插入和删除元素,因为其大小是固定的。
- 两端插入/删除性能:不支持插入和删除元素。
- 内存管理特点:静态存储,内存分配在栈上(如果是局部
array
)或静态存储区(如果是全局array
),内存连续,大小固定。 - 迭代器类型:随机访问迭代器。
- 适用场景:适用于元素数量固定,需要快速随机访问元素的场景,例如存储一组已知大小的元素,并且不允许元素数量变化,对性能要求较高。
二、关联容器
map:
- 存储结构:基于红黑树实现,红黑树是一种自平衡二叉搜索树,每个节点存储一个键值对,根据键的大小排序。
- 随机访问性能:不支持随机访问,查找元素根据键的顺序进行,时间复杂度为 O ( log n ) O(\log n) O(logn)。使用
map[key]
或map.find(key)
查找元素。 - 中间插入/删除性能:插入和删除元素需要调整树的结构,以保持平衡,时间复杂度为 O ( log n ) O(\log n) O(logn)。例如,使用
map.insert({key, value})
插入元素。 - 两端插入/删除性能:不适用,因为元素是按键的顺序存储,不是按位置存储。
- 内存管理特点:节点存储元素,根据键的顺序动态分配内存,为了保持树的平衡,可能会频繁进行内存分配和释放操作。
- 迭代器类型:双向迭代器,可以按顺序遍历元素。
- 适用场景:适用于存储键值对,键唯一,需要根据键快速查找、插入和删除元素,且元素按关键字有序存储,需要按序遍历元素的场景,例如存储配置信息,根据键查找相应的值。
set:
- 存储结构:与
map
类似,也是基于红黑树实现,但只存储键,不存储值,键即元素。 - 随机访问性能:不支持随机访问,查找元素根据键的顺序进行,时间复杂度为 O ( log n ) O(\log n) O(logn)。使用
set.find(key)
查找元素。 - 中间插入/删除性能:插入和删除元素需要调整树的结构,以保持平衡,时间复杂度为 O ( log n ) O(\log n) O(logn)。例如,使用
set.insert(key)
插入元素。 - 两端插入/删除性能:不适用,因为元素是按键的顺序存储,不是按位置存储。
- 内存管理特点:节点存储元素,根据键的顺序动态分配内存,为了保持树的平衡,可能会频繁进行内存分配和释放操作。
- 迭代器类型:双向迭代器,可以按顺序遍历元素。
- 适用场景:适用于存储唯一的关键字集合,需要按关键字有序存储和快速查找元素的场景,例如存储一组不重复的关键字,对关键字进行有序遍历。
- 存储结构:与
multimap:
- 存储结构:基于红黑树实现,允许键重复的键值对容器。
- 随机访问性能:不支持随机访问,查找元素根据键的顺序进行,时间复杂度为 $O(\log n)
。使用
multimap.find(key)` 查找元素。 - 中间插入/删除性能:插入和删除元素需要调整树的结构,以保持平衡,时间复杂度为 O ( log n ) O(\log n) O(logn)。例如,使用
multimap.insert({key, value})
插入元素。 - 两端插入/删除性能:不适用,因为元素是按键的顺序存储,不是按位置存储。
- 内存管理特点:节点存储元素,根据键的顺序动态分配内存,为了保持树的平衡,可能会频繁进行内存分配和释放操作。
- 迭代器类型:双向迭代器,可以按顺序遍历元素。
- 适用场景:适用于存储多个具有相同关键字的键值对,需要根据键查找元素,且元素按关键字有序存储,需要按序遍历元素的场景,例如存储多个具有相同键的信息,如存储一个单词在文本中出现的多个位置。
multiset:
- 存储结构:与
multimap
类似,基于红黑树,允许键重复,只存储键。 - 随机访问性能:不支持随机访问,查找元素根据键的顺序进行,时间复杂度为 $O(\log n)
。使用
multiset.find(key)` 查找元素。 - 中间插入/删除性能:插入和删除元素需要调整树的结构,以保持平衡,时间复杂度为 O ( log n ) O(\log n) O(logn)。例如,使用
multiset.insert(key)
插入元素。 - 两端插入/删除性能:不适用,因为元素是按键的顺序存储,不是按位置存储。
- 内存管理特点:节点存储元素,根据键的顺序动态分配内存,为了保持树的平衡,可能会频繁进行内存分配和释放操作。
- 迭代器类型:双向迭代器,可以按顺序遍历元素。
- 适用场景:适用于存储允许重复的关键字集合,需要按关键字有序存储和快速查找元素的场景,例如存储一组允许重复的关键字,对关键字进行有序遍历。
- 存储结构:与
三、无序集合
unordered_map:
- 存储结构:基于哈希表实现,元素存储在桶中,通过哈希函数将键映射到桶中。
- 随机访问性能:不支持随机访问,平均查找时间复杂度为 O ( 1 ) O(1) O(1),但在最坏情况下(哈希冲突严重)为 O ( n ) O(n) O(n)。使用
unordered_map[key]
或unordered_map.find(key)
查找元素。 - 中间插入/删除性能:平均情况下插入和删除元素时间复杂度为 O ( 1 ) O(1) O(1),最坏情况下为 O ( n ) O(n) O(n)。例如,使用
unordered_map.insert({key, value})
插入元素。 - 两端插入/删除性能:不适用,因为元素是根据哈希函数存储,不是按位置存储。
- 内存管理特点:使用桶存储元素,根据元素的哈希值分配到不同的桶中,可能会有较多的内存开销,尤其是哈希冲突严重时,需要处理冲突。
- 迭代器类型:前向迭代器,可以遍历元素,但不支持随机访问。
- 适用场景:适用于存储键值对,键唯一,需要根据键快速查找、插入和删除元素,不要求元素有序存储的场景,例如快速查找键值对,对性能要求高,不需要元素有序。
unordered_set:
- 存储结构:基于哈希表实现,只存储键,不存储值。
- 随机访问性能:不支持随机访问,平均查找时间复杂度为 O ( 1 ) O(1) O(1),但在最坏情况下为 O ( n ) O(n) O(n)。使用
unordered_set.find(key)
查找元素。 - 中间插入/删除性能:平均情况下插入和删除元素时间复杂度为 O ( 1 ) O(1) O(1),最坏情况下为 O ( n ) O(n) O(n)。例如,使用
unordered_set.insert(key)
插入元素。 - 两端插入/删除性能:不适用,因为元素是根据哈希函数存储,不是按位置存储。
- 内存管理特点:使用桶存储元素,根据元素的哈希值分配到不同的桶中,可能会有较多的内存开销,尤其是哈希冲突严重时,需要处理冲突。
- 迭代器类型:前向迭代器,可以遍历元素,但不支持随机访问。
- 适用场景:适用于存储唯一的关键字集合,需要快速查找元素,不要求元素有序存储的场景,例如存储一组不重复的关键字,快速查找关键字是否存在。
unordered_multimap:
- 存储结构:基于哈希表实现,允许键重复的键值对容器。
- 随机访问性能:不支持随机访问,平均查找时间复杂度为 O ( 1 ) O(1) O(1),但在最坏情况下为 O ( n ) O(n) O(n)。使用
unordered_multimap.find(key)
查找元素。 - 中间插入/删除性能:平均情况下插入和删除元素时间复杂度为 O ( 1 ) O(1) O(1),最坏情况下为 O ( n ) O(n) O(n)。例如,使用
unordered_multimap.insert({key, value})
插入元素。 - 两端插入/删除性能:不适用,因为元素是根据哈希函数存储,不是按位置存储。
- 内存管理特点:使用桶存储元素,根据元素的哈希值分配到不同的桶中,可能会有较多的内存开销,尤其是哈希冲突严重时,需要处理冲突。
- 迭代器类型:前向迭代器,可以遍历元素,但不支持随机访问。
- 适用场景:适用于存储多个具有相同关键字的键值对,需要快速查找元素,不要求元素有序存储的场景,例如存储多个具有相同关键字的键值对,快速查找具有某个关键字的键值对。
unordered_multiset:
- 存储结构:基于哈希表实现,允许键重复,只存储键。
- 随机访问性能:不支持随机访问,平均查找时间复杂度为 O ( 1 ) O(1) O(1),但在最坏情况下为 O ( n ) O(n) O(n)。使用
unordered_multiset.find(key)
查找元素。 - 中间插入/删除性能:平均情况下插入和删除元素时间复杂度为 O ( 1 ) O(1) O(1),最坏情况下为 O ( n ) O(n) O(n)。例如,使用
unordered_multiset.insert(key)
插入元素。 - 两端插入/删除性能:不适用,因为元素是根据哈希函数存储,不是按位置存储。
- 内存管理特点:使用桶存储元素,根据元素的哈希值分配到不同的桶中,可能会有较多的内存开销,尤其是哈希冲突严重时,需要处理冲突。
- 迭代器类型:前向迭代器,可以遍历元素,但不支持随机访问。
- 适用场景:适用于存储允许重复的关键字集合,需要快速查找元素,不要求元素有序存储的场景,例如存储一组允许重复的关键字,快速查找关键字是否存在。