
【STL】顺序容器之deque用法总结
双向操作:deque允许在头尾两端分别进行元素插入和删除操作,这使得它在某些场景下比传统的向量更高效。 动态分配:与向量不同,deque没有固定的容量概念。它通过动态分配内存块,随时扩展或收缩存储空间,避免了传统向量重新配置内存的开销。 实现复杂度:虽然deque支持随机访问,但其实现复杂度远高于向量和列表(list),因为需要维护一系列指针和缓冲区以保持连续性。
发布日期:2021-05-08 01:38:07
浏览次数:23
分类:精选文章
本文共 2639 字,大约阅读时间需要 8 分钟。
C++ deque 数据结构详解
deque(双端队列)是一种高效的容器,支持在队首和队尾快速插入和删除操作。它与传统的向量(vector)相比,具有显著的优势,适合需要频繁在两端操作数据的场景。本文将详细介绍deque的基本原理、使用方法、时间复杂度以及注意事项。
一、基本原理
deque是一种双向开口的连续线性空间,支持在头部和尾部进行元素插入和删除操作。其最大特点在于:
deque的核心结构由两部分组成:
- 主控块:一小块存储空间,用于存储指针,指向另一段较大的连续缓冲区。
- 缓冲区:deque的实际存储空间,包含多个连续的线性块。
二、用法
1. 初始化
创建一个deque实例,可以通过以下方式:
deque d1; // 创建一个空队列deque d1(100, 7); // 初始化包含100个7的队列deque d1{1, 2, 3, ...}; // 初始化包含元素1, 2, 3...的队列deque d2(d1); // 拷贝d1到d2deque d2 = d1; // 将d1赋值给d2
2. 访问元素
通过索引或迭代器访问元素:
int elem = d1[5]; // 根据索引访问元素int elem = d1.at(5); // 根据索引访问元素(越界会抛出异常)int first = d1.front(); // 访问队首元素int last = d1.back(); // 访问队尾元素
获取迭代器:
auto iter = d1.begin(); // 队首的迭代器auto end = d1.end(); // 队尾元素的后一个位置auto riter = d1.rbegin(); // 队首元素的前一个位置auto rend = d1.rend(); // 队尾元素的迭代器auto citer = d1.cbegin(); // 常量迭代器指向队首元素auto crediter = d1.cend(); // 常量迭代器指向队尾元素的后一个位置
3. 遍历容器
使用普通for循环或范围for语句:
for (int i = 0; i < d1.size(); ++i) { cout << d1[i] << endl;}for (deque ::iterator iter = d1.begin(); iter != d1.end(); ++iter) { cout << *iter << endl;}for (auto it : d1) { cout << it << endl;}
4. 添加与删除元素
添加元素
d1.push_front(10); // 队首添加元素d1.emplace_front(10); // 队首添加元素(更灵活)d1.push_back(20); // 队尾添加元素d1.emplace_back(20); // 队尾添加元素(更灵活)d1.insert(d1.begin(), 10); // 在队首插入元素d1.insert(d1.end(), 3, 5); // 队尾插入多个元素
删除元素
d1.pop_front(); // 队首删除元素d1.pop_back(); // 队尾删除元素d1.erase(iter); // 删除指定迭代器指向的元素d1.erase(iter1, iter2); // 删除迭代器范围内的元素d1.clear(); // 删除所有元素
5. 替换元素
d1 = d2; // 将d1替换为d2的元素d1.swap(d2); // 交换d1和d2的元素d1.resize(5, 0); // 调整大小为5,新元素初始化为0d1.assign(iter1, iter2); // 替换元素d1.assign(5, 0); // 替换为5个0d1.assign({1, 2, 3, 4, 5}); // 替换为指定列表
6. deque的大小
int size = d1.size(); // 获取实际使用的元素数目int capacity = d1.max_size(); // 获取可存储最大元素数目d1.shrink_to_fit(); // 释放不必要的内存d1.resize(10); // 调整大小为10d1.resize(10, -5); // 调整大小为10,新元素初始化为-5
三、时间复杂度
操作 | 时间复杂度 |
---|---|
随机访问 | O(1) |
查找(find等) | O(n) |
队首或队尾插入/删除 | O(1) |
其他操作(如插入/删除中间) | O(n) |
四、注意事项
1. 下标越界
d1[n]
:越界时行为未定义。d1.at(n)
:越界时抛出out_of_range
异常。
2. 迭代器失效
deque和string:插入或删除非首尾元素会使所有迭代器失效。
deque:插入或删除尾部元素仅会使尾迭代器失效。
list和forward_list:插入或删除元素不会使迭代器失效。
删除元素后:
- deque和string:删除尾元素会使尾迭代器失效。
- deque:删除非首尾元素会使所有迭代器失效,删除首元素则不会。
通过合理使用deque,可以充分发挥其高效操作的优势,同时注意迭代器的有效性管理。