一.std 容器 C++ 标准库提供了多种容器类型,每种容器都有不同的实现原理、性能特性以及适用的场景。常见的 std 容器包括顺序容器、关联容器、无序容器和适配器容器。下面是一些常见容器的介绍。
- 顺序容器(Sequence Containers)
顺序容器按照元素的插入顺序保存元素,元素的访问通常是按顺序进行。
(1) std::vector
实现原理:std::vector 是基于动态数组实现的。它在内存中是连续存储的,当元素数量增加时,如果容量不够,会自动重新分配更大的内存空间并将数据复制过来。
性能:
随机访问:O(1),非常快速。
插入或删除:在尾部插入或删除是 O(1),但在中间插入或删除是 O(n)。
扩容时:可能需要重新分配内存,导致性能下降。
使用场景:适用于需要频繁访问元素或追加元素的场景,特别是需要支持快速随机访问时。
(2) std::deque
实现原理:std::deque(双端队列)是由一系列固定大小的数组块组成的,每个块存储一部分数据。它支持在两端进行高效插入和删除。
性能:
随机访问:O(1)。
在两端插入或删除:O(1)。
中间插入或删除:O(n)。
使用场景:适用于需要从两端进行频繁插入或删除操作的场景。
(3) std::list
实现原理:std::list 是基于双向链表实现的。每个元素都有两个指针,分别指向前一个和后一个元素。
性能:
随机访问:不支持随机访问,访问时间是 O(n)。
插入或删除:在任意位置的插入或删除是 O(1)(如果已定位到元素)。
使用场景:适用于需要频繁插入或删除元素的场景,尤其是需要在中间频繁插入和删除的情况。
(4) std::array
实现原理:std::array 是一个封装了固定大小数组的容器,大小在编译时确定,不支持动态扩展。
性能:
随机访问:O(1)。
插入或删除:不支持,大小固定。
使用场景:适用于已知大小并且元素数量在编译时确定的场景。
2. 关联容器(Associative Containers)
关联容器根据元素的键(key)进行存储,支持高效查找、插入和删除。 (1) std::set
实现原理:std::set 是基于平衡二叉搜索树(通常是红黑树)实现的。元素按键自动排序且不允许重复元素。
性能:
查找、插入和删除:O(log n)。
使用场景:适用于需要自动排序且不允许重复元素的场景,常用于快速查找和去重。
(2) std::map
实现原理:std::map 是基于平衡二叉搜索树(通常是红黑树)实现的,键值对按键自动排序。
性能:
查找、插入和删除:O(log n)。
使用场景:适用于需要基于键值对存储数据并自动排序的场景,常用于字典、查找表等。
(3) std::multiset
实现原理:std::multiset 类似于 std::set,但允许重复元素。
性能:
查找、插入和删除:O(log n)。
使用场景:适用于需要自动排序且允许重复元素的场景。
(4) std::multimap
实现原理:std::multimap 类似于 std::map,但允许键重复。
性能:
查找、插入和删除:O(log n)。
使用场景:适用于需要基于键值对存储数据并允许多个相同键的场景。
3. 无序容器(Unordered Containers)
无序容器使用哈希表来存储元素,提供平均 O(1) 时间复杂度的查找、插入和删除操作,但不保持元素的顺序。 (1) std::unordered_set
实现原理:std::unordered_set 基于哈希表实现,元素按哈希值存储。
性能:
查找、插入和删除:平均 O(1),最坏情况是 O(n)(当发生哈希冲突时)。
使用场景:适用于需要快速查找并且元素不要求有顺序的场景。
(2) std::unordered_map
实现原理:std::unordered_map 基于哈希表实现,键值对按键的哈希值存储。
性能:
查找、插入和删除:平均 O(1),最坏情况是 O(n)。
使用场景:适用于需要快速查找并且键值对元素不要求有顺序的场景。
(3) std::unordered_multiset
实现原理:std::unordered_multiset 基于哈希表实现,允许重复元素。
性能:
查找、插入和删除:平均 O(1),最坏情况是 O(n)。
使用场景:适用于需要快速查找并且允许重复元素且不关心顺序的场景。
(4) std::unordered_multimap
实现原理:std::unordered_multimap 基于哈希表实现,允许重复键。
性能:
查找、插入和删除:平均 O(1),最坏情况是 O(n)。
使用场景:适用于需要快速查找并且允许重复键且不关心顺序的场景。
4. 适配器容器(Container Adapters)
适配器容器是对其他容器的封装,提供了特定的接口和行为。 (1) std::stack
实现原理:std::stack 是基于其他容器(如 std::deque 或 std::vector)实现的,提供栈(LIFO)结构。
性能:
操作:push、pop 和 top 都是 O(1)。
使用场景:适用于需要栈结构的场景,如深度优先搜索(DFS)等。
(2) std::queue
实现原理:std::queue 基于双端队列(std::deque)或其他容器实现,提供队列(FIFO)结构。
性能:
操作:push 和 pop 都是 O(1)。
使用场景:适用于需要队列结构的场景,如广度优先搜索(BFS)等。
(3) std::priority_queue
实现原理:std::priority_queue 基于堆(通常是最大堆或最小堆)实现,提供优先队列结构。
性能:
插入:O(log n)。
弹出最大/最小元素:O(log n)。
使用场景:适用于需要按优先级处理元素的场景,如任务调度等。
总结
顺序容器:适用于需要按顺序存储并快速访问的场景,如 std::vector、std::deque。
关联容器:适用于需要基于键值对存储数据并按键排序的场景,如 std::map、std::set。
无序容器:适用于需要高效查找但不关心元素顺序的场景,如 std::unordered_map、std::unordered_set。
适配器容器:提供特定数据结构接口的容器,适用于栈、队列和优先队列等特殊需求。