目录
一、描述
std::deque
(双端队列)是 C++ 标准模板库(STL)中的一个序列容器,它支持在容器的前端和后端高效地插入和删除元素。与 std::vector
不同,std::deque
不需要预先分配大块连续内存,因此它在某些情况下可以提供更灵活的内存管理。
以下是对 std::deque
的详细使用说明
二、包含头文件
要使用 std::deque
,首先需要包含头文件 <deque>;
如果使用 using namespace std;的话, 使用deque的时候可以不用在前面增加:std::
#include <deque>
using namespace std;
三、创建和初始化
默认构造函数
创建一个空的 deque
deque<int> dq;
带数据进行初始化
// 创建一个包含5个元素的deque,每个元素的值都是10
deque<int> dq(5, 10);
拷贝构造函数进行初始化
从另一个 deque
创建新的 deque
deque<int> dq1(5, 10);
deque<int> dq2 = dq1; // dq2 是 dq1 的拷贝
迭代器范围构造函数
使用两个迭代器之间的元素来初始化 deque
begin(),表示vec的开始位置, end(),表示vec的结束位置
vector<int> vec = {1, 2, 3, 4, 5};
deque<int> dq(vec.begin(), vec.end());
四、元素访问
使用下标访问
可以像数组一样使用下标访问元素(注意:下标从0开始)
dq[0] = 10; // 访问并修改第一个元素
int value = dq[2]; // 访问第三个元素
使用成员函数 at进行访问
使用 at 方法访问元素,如果下标越界会抛出 std::out_of_range 异常
// 访问第三个元素,众所周知索引从0开始
int value = dq.at(2);
使用前向和后向迭代器
使用迭代器遍历 deque
//这里可以使用auto, 或者iterator
for (auto it = dq.begin(); it != dq.end(); ++it)
{
cout << *it << " ";
}
//或
for (deque<int>::iterator it = dq.begin(); it != dq.end(); ++it)
{
cout << *it << " ";
}
五、容器操作
1、size
返回deque容器的数量
size_t num_elements = dq.size();
2、empty
判断deque是否为空
bool isEmpty = dq.empty();
3、max_size
返回 deque
可能包含的最大元素数量(通常是一个非常大的值)
size_t max_size = dq.max_size();
六、修改器
1、clear
清空deque
dq.clear();
2、insert
在指定位置插入一个或多个元素
// 在第三个位置插入100
dq.insert(dq.begin() + 2, 100);
// 在末尾插入两个元素
dq.insert(dq.end(), {200, 300});
3、erase
删除指定位置的元素或元素范围
// 删除第三个元素
dq.erase(dq.begin() + 2);
// 删除前两个元素
dq.erase(dq.begin(), dq.begin() + 2);
4、push_back 和 pop_back
在 deque 的末尾添加或删除元素
// 在末尾添加元素100
dq.push_back(100);
// 删除末尾元素
dq.pop_back();
5、push_front 和 pop_front
在 deque 的前端添加或删除元素
// 在前端添加元素100
dq.push_front(100);
// 删除前端元素
dq.pop_front();
6、front 和 back
访问 deque 的前端和后端元素
int front_value = dq.front();
int back_value = dq.back();
七、非成员函数
1、begin 和 end
返回指向 deque 第一个元素和最后一个元素之后位置的迭代器
auto it_begin = dq.begin();
auto it_end = dq.end();
2、rbegin 和 rend
返回指向 std::deque 最后一个元素和第一个元素之前位置的反向迭代器
auto it_rbegin = dq.rbegin();
auto it_rend = dq.rend();
3、emplace
在指定位置直接构造元素(通常比 insert 更高效)
// 在第三个位置直接构造并插入元素100
dq.emplace(dq.begin() + 2, 100);
4、emplace_back 和 emplace_front
在 deque 的末尾或前端直接构造元素
// 在末尾直接构造并插入元素100
dq.emplace_back(100);
// 在前端直接构造并插入元素100
dq.emplace_front(100);
八、示例代码
以下是一个完整的示例代码,展示了如何使用 deque
#include <iostream>
#include <deque>
using namespace std;
int main()
{
deque<int> dq;
// 插入元素
dq.push_back(10);
dq.push_front(5);
dq.emplace_back(20);
dq.emplace(dq.begin() + 1, 15);
// 访问元素
cout << "Front: " << dq.front() << endl;
cout << "Back: " << dq.back() << endl;
cout << "Element at index 2: " << dq[2] << endl;
// 遍历元素
for (int value : dq)
{
cout << value << " ";
}
cout << endl;
// 删除元素
dq.pop_front();
dq.erase(dq.begin() + 1);
// 再次遍历元素
for (int value : dq)
{
cout << value << " ";
}
cout << endl;
return 0;
}
九、迭代器的使用
deque
提供了双向迭代器,这意味着你可以向前或向后遍历容器中的元素。迭代器类型可以通过deque
的成员类型iterator
和const_iterator
来获得。
1、获取迭代器
begin():返回一个指向容器第一个元素的迭代器。
end():返回一个指向容器最后一个元素之后位置的迭代器(这是一个“尾后”迭代器,不指向任何有效元素)。
rbegin():返回一个指向容器最后一个元素的反向迭代器。
rend():返回一个指向容器第一个元素之前位置的反向迭代器(这也是一个“尾后”迭代器)。
2、使用迭代器遍历
下面是一个使用迭代器遍历std::deque的示例代码
#include <iostream>
#include <deque>
using namespace std;
int main()
{
// 创建一个deque并初始化
deque<int> dq = {1, 2, 3, 4, 5};
// 使用正向迭代器遍历
for (deque<int>::iterator it = dq.begin(); it != dq.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
// 使用C++11范围for循环遍历(更简洁)
for (int value : dq)
{
cout << value << " ";
}
cout << endl;
// 使用反向迭代器遍历
for (deque<int>::reverse_iterator rit = dq.rbegin(); rit != dq.rend(); ++rit)
{
cout << *rit << " ";
}
cout << endl;
return 0;
}
3、输出结果
运行以上代码输出的结果是
1 2 3 4 5
1 2 3 4 5
5 4 3 2 1
4、注意事项
- 迭代器失效:在std::deque中插入或删除元素可能会导致指向这些元素的迭代器失效。特别是,如果插入或删除发生在迭代器的当前位置之前,那么该迭代器将不再指向有效的元素。因此,在遍历过程中进行插入或删除操作时需要特别小心。
- 常量性:如果你只需要读取容器中的元素而不修改它们,那么应该使用const_iterator来遍历容器。这样可以确保你不会意外地修改元素。
- 效率:std::deque的迭代器通常比std::list的迭代器更高效,因为std::deque在内部是以块的形式存储元素的,这些块之间可能通过指针链接起来,但仍然允许一定程度的随机访问。然而,与std::vector相比,std::deque的迭代器可能不如std::vector的迭代器高效,因为std::vector提供了连续的内存布局。
- 总之,使用迭代器遍历std::deque是一种强大且灵活的方式,可以高效地访问和操作容器中的元素。