目录
一、vector容器与list容器的优缺点
1. 存储结构
- vector:底层使用动态数组实现,内存连续。
- list:底层使用双向链表实现,内存不连续。
2. 内存管理
- vector:
- 动态数组,如果需要扩展容量,会重新分配更大的内存,并复制原有元素,效率较低。
- 访问元素时,连续内存有助于缓存命中,访问速度较快。
- list:
- 每个元素存储在一个独立的节点中,每个节点包含指向前后节点的指针。
- 插入和删除操作不需要大量内存复制,只需修改指针,效率较高。
3. 时间复杂度
- vector:
- 访问元素:O(1)(通过下标直接访问)
- 插入和删除(在末尾):O(1)
- 插入和删除(在中间):O(n)(需要移动元素)
- list:
- 访问元素:O(n)(需要遍历)
- 插入和删除(在任意位置):O(1)(只需调整指针)
4. 插入和删除操作
- vector:
- 在末尾插入和删除操作效率高,代价为常数时间。
- 在中间插入和删除元素需要移动其他元素,效率低。
- list:
- 插入和删除操作只需调整指针,无需移动其他元素,效率高。
5. 内存占用
- vector:
- 内存占用较紧凑,除了存储数据外,没有额外的指针开销。
- 需要预留额外的空间来处理动态扩展。
- list:
- 每个节点除了存储数据外,还包含两个指针(前驱和后继),额外的内存开销较大。
6. 使用场景
- vector:
- 适用于频繁访问元素、少量插入和删除操作的场景。
- 比如:需要随机访问的数组、栈等。
- list:
- 适用于频繁插入和删除操作、较少访问元素的场景。
- 比如:需要频繁插入删除的队列、链表等。
总结
- 如果你的应用程序需要快速随机访问元素,并且插入和删除操作较少,
vector
是更好的选择。- 如果你的应用程序需要频繁插入和删除元素,并且不需要随机访问,
list
更合适。
正因如此,创作者想能否设计一种结构能兼顾vector的快速随机访问以及list快速插入删除的优点。于是deque容器应运而生。
二、容器设计
2.1 底层结构
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。
2.2 迭代器设计
2.3 优缺点
- 与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。
- 与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多。
三、使用
3.1 构造函数
与vector类完全一致
3.2 访问与遍历
大致与vector类完全一致,增加了类似list类中的接口
- 除了用迭代器获取deque容器中元素,[ ]和at也可以
- front返回容器第一个元素
- back返回容器最后一个元素
3.3 容量操作
- deque没有容量的概念
- 判断是否为空 — empty
- 返回元素个数 — size
- 重新指定个数 — resize
3.4 增删查改
与list类一致
- 插入和删除提供的位置是迭代器!
- 尾插 — push_back
- 尾删 — pop_back
- 头插 — push_front
- 头删 — pop_front