std::deque
(双端队列)是C++标准库中的一个容器,它允许我们在队列的两端快速插入和删除元素,同时还提供了随机访问的能力。std::deque
的内部结构以及它是如何平衡随机访问和插入/删除性能的,是一个相当有趣且值得深入了解的话题。
std::deque的内部结构
std::deque
通常是由多个固定大小的数组(或称为块/chunk)组成的,每个数组内部存储了deque的一部分元素。这些数组以双向链表的形式连接起来,形成一个连续的元素序列。每个数组(块)的大小通常是由实现定义的,但一般足够大以减少内存分配的开销。
由于std::deque
的这种分段连续存储结构,它能够在两端快速添加或删除元素,而不需要移动其他元素。同时,通过维护指向各个块的指针数组,std::deque
也支持快速的随机访问。
平衡随机访问和插入/删除性能
std::deque
通过其内部结构设计,在随机访问和插入/删除性能之间达到了平衡:
-
随机访问性能:虽然
std::deque
的元素不是连续存储的,但是通过维护一个指向各个存储块的指针数组,它能够实现接近std::vector
的随机访问性能。当我们需要访问某个元素时,std::deque
首先根据索引计算出元素所在的块,然后通过指针数组直接定位到该块,最后在该块内部进行线性搜索找到元素。这种设计使得随机访问的时间复杂度接近O(1)。 -
插入/删除性能:在
std::deque
的两端插入或删除元素时,由于它的分段连续存储结构,通常只需要在链表头部或尾部添加或移除一个块即可,这保证了在两端进行插入和删除操作的时间复杂度为常数级别(O(1))。在deque的中间插入或删除元素会稍微慢一些,因为需要移动元素以保持连续性,但这仍然比std::vector
在中间插入或删除元素要快,因为std::vector
可能需要移动大量元素。
示例代码
下面是一个简单的示例代码,展示了如何使用std::deque
:
#include <iostream>
#include <deque>
int main() {
std::deque<int> myDeque;
// 在deque的尾部插入元素
myDeque.push_back(10);
myDeque.push_back(20);
myDeque.push_back(30);
// 在deque的头部插入元素
myDeque.push_front(5);
myDeque.push_front(0);
// 随机访问deque中的元素
std::cout << "Element at index 2: " << myDeque[2] << std::endl; // 输出30
// 遍历deque并打印所有元素
for (int num : myDeque) {
std::cout << num << " ";
}
std::cout << std::endl; // 输出0 5 10 20 30
// 在deque的头部和尾部删除元素
myDeque.pop_front(); // 删除0
myDeque.pop_back(); // 删除30
// 再次遍历并打印剩余元素
for (int num : myDeque) {
std::cout << num << " ";
}
std::cout << std::endl; // 输出5 10 20
return 0;
}