目录
1.1 constructor、destructor、operator=
2. Non-member function overloads
deque
template < class T, class Alloc = allocator<T> > class deque;
deque(通常发音为 "deck")是双端队列的不规则缩写。双端队列是具有动态大小的序列容器,可以在两端(前端或后端)扩展或收缩。
特定的库可能以不同的方式实现deque,通常是某种形式的动态数组。但无论如何,它们都允许通过随机访问迭代器直接访问单个元素,并根据需要通过扩展和收缩容器自动处理存储。
因此,它们提供了与vector类似的功能,但可以在序列的开头(而不仅仅是结尾)有效地插入和删除元素。但是,与vector不同,deque不能保证将所有元素存储在连续的存储位置:通过偏移指向另一个元素的指针来访问deque中的元素会导致未定义的行为。
vector和deque都提供了非常相似的接口,可以用于类似的目的,但两者的内部工作方式截然不同: vector使用的是单个数组,偶尔需要重新分配以满足增长的需要,而deque的元素可以分散在不同的存储块中,容器内部保留了必要的信息,可以在恒定时间内通过统一的顺序接口(通过迭代器)直接访问其中的任何元素。因此,deque的内部结构要比vector复杂一些,但这使得它们在某些情况下能够更有效地增长,特别是在序列很长的情况下,重新分配的代价会更高。
对于在开头或结尾以外的位置频繁插入或移除元素的操作,deque的性能比list和forward_list差,迭代器和引用也不一致。
deque定义在头文件deque和命名空间std中。
1. Member functions
1.1 constructor、destructor、operator=
1.1.1 constructor
// default (1)
explicit deque(const allocator_type & alloc = allocator_type());
// fill(2)
explicit deque(size_type n);
deque(size_type n, const value_type & val, const allocator_type & alloc = allocator_type());
// range (3)
template <class InputIterator> deque(InputIterator first, InputIterator last, const allocator_type & alloc = allocator_type());
// copy (4)
deque(const deque & x);
deque(const deque & x, const allocator_type & alloc);
// move (5)
deque(deque && x);
deque(deque && x, const allocator_type & alloc);
// initializer list (6)
deque(initializer_list<value_type> il, const allocator_type & alloc = allocator_type());
#include <deque>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq1; // default
printDq(dq1); // 空
deque<int> dq2(5); // fill
printDq(dq2); // 0 0 0 0 0
deque<int> dq3(10, 1); // fill
printDq(dq3); // 1 1 1 1 1 1 1 1 1 1
string s("hello world");
deque<char> dq4(s.begin() + 3, --s.end()); // range
printDq(dq4); // l o w o r l
deque<char> dq5(dq4); // copy
// 等价于deque<char> dq5 = dq4;
printDq(dq5); // l o w o r l
deque<char> dq6(std::move(dq5)); // move
cout << "dq5: "; printDq(dq5); // dq5:
cout << "dq6: "; printDq(dq6); // dq6: l o w o r l
deque<string> dq7{ "happy","new","year" }; // initializer list
// 等价于deque<string> dq7 = { "happy","new","year" };
printDq(dq7); // happy new year
return 0;
}
1.1.2 destructor
~deque();
1.1.3 operator=
// copy (1)
deque& operator=(const deque& x);
// move (2)
deque& operator=(deque&& x);
// initializer list (3)
deque& operator=(initializer_list<value_type> il);
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq(5, 2);
printDq(dq); // 2 2 2 2 2
deque<int> dq1;
dq1 = dq; // copy
printDq(dq1); // 2 2 2 2 2
deque<int> dq2;
dq2 = std::move(dq1); // move
cout << "dq1: "; printDq(dq1); // dq1:
cout << "dq2: "; printDq(dq2); // dq2: 2 2 2 2 2
deque<int> dq3;
dq3 = { 1,2,3,4,5,6 }; // initializer list
printDq(dq3); // 1 2 3 4 5 6
return 0;
}
1.2 Iterators
// begin
iterator begin() noexcept;
const_iterator begin() const noexcept;
// end
iterator end() noexcept;
const_iterator end() const noexcept;
// rbegin
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
// rend
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
// cbegin
const_iterator cbegin() const noexcept;
// cend
const_iterator cend() const noexcept;
// crbegin
const_reverse_iterator crbegin() const noexcept;
// crend
const_reverse_iterator crend() const noexcept;
函数 | 功能 |
---|---|
& | begin返回一个迭代器,指向deque对象的第一个元素 end返回一个迭代器,指向deque对象的最后一个元素的下一个位置 |
& | rbegin返回一个反向迭代器,指向deque对象的最后一个元素 rend返回一个反向迭代器,指向deque对象的第一个元素的上一个位置 |
& | cbegin返回一个const迭代器,指向deque对象的第一个元素 cend返回一个const迭代器,指向deque对象的最后一个元素的下一个位置 |
& | crbegin返回一个const反向迭代器,指向deque对象的最后一个元素 crend返回一个const反向迭代器,指向deque对象的第一个元素的上一个位置 |
begin&end和rbegin&rend返回的迭代器指向:
const_iterator是一个指向const内容的迭代器。迭代器本身可以修改,但是它不能被用来修改它所指向的内容。
begin&end/rbegin&rend和cbegin&cend/crbegin&crend的不同:
- begin&end/rbegin&rend的返回类型由对象是否是常量来决定。如果不是常量,返回iterator;如果是常量,返回const_iterator。
- cbegin&cend/crbegin&crend的返回类型是const_iterator,不管对象本身是否是常量。
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 1,2,3,4 };
deque<int>::iterator it = dq.begin();
while (it != dq.end())
{
cout << *it << " ";
++it;
}
cout << endl;
// 1 2 3 4
auto rit = dq.rbegin();
// deque<int>::reverse_iterator rit = dq.rbegin();
while (rit != dq.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
// 4 3 2 1
return 0;
}
1.3 Capacity
1.3.1 size
size_type size() const noexcept;
// 返回deque中元素的个数
1.3.2 max_size
size_type max_size() const noexcept;
// 返回deque能够容纳的最大元素个数
1.3.3 resize
void resize(size_type n);
void resize(size_type n, const value_type& val);
// 调整deque的大小为n
// 如果n<当前的大小,多余的元素会被截掉
// 如果n>当前的大小,则:
// 1)如果没有指定填充元素,则使用默认构造函数
// 2)如果指定了填充元素val,则多出的空间用val填充
1.3.4 empty
bool empty() const noexcept;
// 检测deque是否为空,是返回true,否则返回false
1.3.5 shrink_to_fit
void shrink_to_fit();
// 收缩容量以适应vector的大小
// 这个请求没有约束力,容器实现可以自由地进行优化,使容量大于其大小
Capacity系列函数使用示例:
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq(3, 6);
cout << dq.size() << endl; // 3
cout << dq.max_size() << endl; // 1073741823
dq.resize(8, 7);
printDq(dq); // 6 6 6 7 7 7 7 7
dq.resize(5);
printDq(dq); // 6 6 6 7 7
if (dq.empty())
cout << "deque为空" << endl;
else
cout << "deque不为空" << endl;
// deque不为空
return 0;
}
1.4 Element access
1.4.1 operator[]
reference operator[](size_type n);
const_reference operator[](size_type n) const;
// 返回deque中n位置的元素的引用
// 没有越界检查
1.4.2 at
reference at(size_type n);
const_reference at(size_type n) const;
// 返回deque中n位置的元素的引用
// 有越界检查,如果越界会抛异常
1.4.3 front
reference front();
const_reference front() const;
// 返回deque中第一个元素的引用
1.4.4 back
reference back();
const_reference back() const;
// 返回deque中最后一个元素的引用
Element access系列函数使用示例:
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 1,2,3,4 };
cout << dq[0] << endl; // 1
cout << dq.at(1) << endl; // 2
cout << dq.front() << endl; // 1
cout << dq.back() << endl; // 4
return 0;
}
1.5 Modifiers
1.5.1 assign
// range (1)
template <class InputIterator> void assign(InputIterator first, InputIterator last);
// fill (2)
void assign(size_type n, const value_type& val);
// initializer list (3)
void assign(initializer_list<value_type> il);
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq1{ 1,2,3,4 };
deque<int> dq2{ 5,6,7,8,9 };
dq1.assign(dq2.begin() + 2, --dq2.end()); // range
printDq(dq1); // 7 8
dq1.assign(10, 1); // fill
printDq(dq1); // 1 1 1 1 1 1 1 1 1 1
dq1.assign({ 77,88 }); // initializer list
printDq(dq1); // 77 88
return 0;
}
1.5.2 push_back
void push_back(const value_type& val);
void push_back(value_type&& val);
// 尾插
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq{ 1,2,3,4 };
int val = 5;
dq.push_back(val);
printDq(dq); // 1 2 3 4 5
dq.push_back(6);
printDq(dq); // 1 2 3 4 5 6
return 0;
}
1.5.3 push_front
void push_front(const value_type& val);
void push_front(value_type&& val);
// 头插
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq{ 2,3,4 };
int val = 1;
dq.push_front(val);
printDq(dq); // 1 2 3 4
dq.push_front(0);
printDq(dq); // 0 1 2 3 4
return 0;
}
1.5.4 pop_back
void pop_back();
// 尾删
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq{ 1,2,3,4 };
dq.pop_back();
printDq(dq); // 1 2 3
dq.pop_back();
printDq(dq); // 1 2
return 0;
}
1.5.5 pop_front
void pop_front();
// 头删
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq{ 1,2,3,4 };
dq.pop_front();
printDq(dq); // 2 3 4
dq.pop_front();
printDq(dq); // 3 4
return 0;
}
1.5.6 insert
// single element(1)
iterator insert(const_iterator position, const value_type& val);
// fill(2)
iterator insert(const_iterator position, size_type n, const value_type& val);
// range(3)
template <class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last);
// move(4)
iterator insert(const_iterator position, value_type&& val);
// initializer list(5)
iterator insert(const_iterator position, initializer_list<value_type> il);
// 在position位置插入
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq1{ 1,2,3,4 };
deque<int> dq2{ 11,22,33,44,55 };
int val = 5;
dq1.insert(dq1.end(), val); // single element
printDq(dq1); // 1 2 3 4 5
dq1.insert(dq1.begin(), 1, 0); // fill
printDq(dq1); // 0 1 2 3 4 5
dq1.insert(dq1.begin() + 3, ++dq2.begin(), --dq2.end()); // range
printDq(dq1); // 0 1 2 22 33 44 3 4 5
dq1.insert(dq1.begin(), 100); // move
printDq(dq1); // 100 0 1 2 22 33 44 3 4 5
dq1.insert(dq1.end(), { 20,21 }); // initializer list
printDq(dq1); // 100 0 1 2 22 33 44 3 4 5 20 21
return 0;
}
1.5.7 erase
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
// 删除
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq{ 0,1,2,3,4 };
dq.erase(dq.begin() + 3);
printDq(dq); // 0 1 2 4
dq.erase(++dq.begin(), --dq.end());
printDq(dq); // 0 4
return 0;
}
1.5.8 swap
void swap(deque& x);
// 交换
#include <deque>
#include <iostream>
using namespace std;
template<typename T>
void printDq(deque<T>& dq)
{
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
deque<int> dq1{ 0,1,2,3,4 };
deque<int> dq2{ 88,99 };
dq1.swap(dq2);
printDq(dq1); // 88 99
printDq(dq2); // 0 1 2 3 4
return 0;
}
1.5.9 clear
void clear() noexcept;
// 清空
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 0,1,2,3,4 };
dq.clear();
if (dq.empty())
cout << "dq被清空" << endl;
else
cout << "dq没被清空" << endl;
// dq被清空
return 0;
}
1.5.10 emplace
template <class... Args> iterator emplace(const_iterator position, Args&&... args);
// 对应insert,区别是:
// 当调用insert时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素
1.5.11 emplace_front
template <class... Args> void emplace_front(Args&&... args);
// 对应push_front,区别是:
// 当调用push_front时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace_front时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素
1.5.12 emplace_back
template <class... Args> void emplace_back(Args&&... args);
// 对应push_back,区别是:
// 当调用push_back时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace_back时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素
1.6 Allocator
1.6.1 get_allocator
allocator_type get_allocator() const noexcept;
// 返回空间配置器
2. Non-member function overloads
2.1 relational operators
// (1)
template <class T, class Alloc> bool operator==(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (2)
template <class T, class Alloc> bool operator!=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (3)
template <class T, class Alloc> bool operator<(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (4)
template <class T, class Alloc> bool operator<=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (5)
template <class T, class Alloc> bool operator>(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
// (6)
template <class T, class Alloc> bool operator>=(const deque<T, Alloc>& lhs, const deque<T, Alloc>& rhs);
2.2 swap
template <class T, class Alloc> void swap (deque<T, Alloc>& x, deque<T, Alloc>& y);
3. deque对象的遍历方法
3.1 operator[]
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 1,2,3,4 };
for (size_t i = 0; i < dq.size(); ++i)
{
cout << dq[i] << " ";
}
cout << endl;
// 1 2 3 4
return 0;
}
3.2 迭代器
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 1,2,3,4 };
deque<int>::iterator it = dq.begin();
while (it != dq.end())
{
cout << *it << " ";
++it;
}
cout << endl;
// 1 2 3 4
auto rit = dq.rbegin();
// deque<int>::reverse_iterator rit = dq.rbegin();
while (rit != dq.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
// 4 3 2 1
return 0;
}
3.3 范围for
#include <deque>
#include <iostream>
using namespace std;
int main()
{
deque<int> dq{ 1,2,3,4 };
for (auto& e : dq)
{
cout << e << " ";
}
cout << endl;
// 1 2 3 4
return 0;
}