deque简单介绍
看到英文不要慌,翻译在下面O(∩_∩)O哈哈~:
- deque(发音类似"deck"),是双端队列不规则的首字母缩写,双端队列是动态大小的序列式容器,其可以向两端进行伸缩。
- 特定的库可以以不同的方式实现deque,但通常都是一种动态数组。不论在何种情况下,它都允许通过随机访问迭代器直接访问单个元素,可以根据需要动态的伸缩。
- 因此,deque提供了一些与vector相似的功能,但deque在头部和尾部进行数据插入和删除操作更加高效。与vector不同的是,deque不能保证所有的元素存储在连续的空间内,在deque中通过指针加偏移量方式访问元素可能会导致非法的操作。
- vector与deque提供了相似的接口,因此其具有类似的用途,但是内部的实现原理不同:vector使用了动态数组,该数组通常需要动态增长;deque中的元素可能分散在不同的存储块中,在deque中保存了一些必要的信息,通常用来在常数范围内直接访问deque中的任何一个元素,所以deque的内部实现比vector更复杂,但是这些额外信息使得deque在某些情况下更加的高效,特别是在序列比较大,重新分配成本比较高的情况下。
- 除了频繁在头部或尾部进行插入和删除的操作外,deque比list和forward_list的性能更差。
deque的使用
构造函数
函数声明 | 接口说明 |
---|
deque(); | 构造空的双端队列 |
deque(n, val = val_type()); | 用n个值为val的元素构造双端队列 |
deque(InputIterator first, InputIterator last); | 用[first, last)的区间构造双端队列 |
deque(const deque& x); | 双端队列的拷贝构造函数 |
#include <iostream>
#include <deque>
void Display(const std::deque<int>& d){
for(const auto& e : d){
std::cout << e << " ";
}
std::cout << std::endl;
}
int main(){
std::deque<int> d1;
Display(d1);
std::deque<int> d2(10, 3);
Display(d2);
int arr[] = {
1, 2, 3, 4, 5
};
std::deque<int> d3(arr, arr + sizeof(arr) / sizeof(arr[0]));
Display(d3);
std::deque<int> d4(d3);
Display(d4);
return 0;
}
[sss@aliyun deque]$ !g++
g++ constructor.cc -o constructor -std=c++11
[sss@aliyun deque]$ ./constructor
3 3 3 3 3 3 3 3 3 3
1 2 3 4 5
1 2 3 4 5
迭代器
双端队列底层是一段假想的连续空间,实际是分段连续的,为了维护其“整体连续”的假象,需要对其迭代器进行特殊处理。
函数声明 | 接口说明 |
---|
[begin(),end()) | begin:容器起始位置;end:最后一个元素的下一个位置。 |
[rbegin(),rend()) | 反向迭代器rbegin在end位置,rend在begin位置。 |
[cbegin(),cend()) | const迭代器,与begin和end位置相同,但不能修改其空间内容。 |
[crbegin(),crend()) | const反向迭代器,crbegin在cend位置,crend在cbegin位置。 |
#include <iostream>
#include <deque>
int main(){
int arr[] = {
1, 2, 3, 4, 5
};
std::deque<int> d(arr, arr + sizeof(arr) / sizeof(arr[0]));
std::deque<int>::iterator it = d.begin();
while(it != d.end()){
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
std::deque<int>::reverse_iterator rit = d.rbegin();
while(rit != d.rend()){
std::cout << *rit << " ";
++rit;
}
std::cout << std::endl;
return 0;
}
[sss@aliyun deque]$ !g++
g++ iterator.cc -o iterator
[sss@aliyun deque]$ ./iterator
1 2 3 4 5
5 4 3 2 1
容量相关操作
函数声明 | 接口说明 |
---|
size(); | 返回deque中有效元素的个数。 |
empty(); | 检测deque是否为空,为空返回true,否则返回false。 |
resize(sz, value); | 将deque中的有效元素数量改变到sz,多出的空间用value填充。 |
#include <iostream>
#include <deque>
int main(){
std::deque<int> d(3, 3);
std::deque<int>::iterator it = d.begin();
while(it != d.end()){
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
std::cout << "empty(): " << d.empty() << std::endl;
std::cout << "size(): " << d.size() << std::endl;
d.resize(4, 4);
it = d.begin();
while(it != d.end()){
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
[sss@aliyun deque]$ !g++
g++ capacity.cc -o capacity
[sss@aliyun deque]$ ./capacity
3 3 3
empty(): 0
size(): 3
3 3 3 4
元素访问操作
函数声明 | 接口说明 |
---|
operator[] | 返回deque中指定位置上元素的引用。 |
front(); | 返回deque中首元素的引用。 |
back(); | 返回deque中最后一个元素的引用。 |
#include <iostream>
#include <deque>
int main(){
int arr[] = {
1, 2, 3, 4, 5
};
std::deque<int> d(arr, arr + sizeof(arr) / sizeof(arr[0]));
for(size_t i = 0; i < d.size(); ++i){
std::cout << d[i] << " ";
}
std::cout << std::endl;
std::cout << "front(): " << d.front() << std::endl;
std::cout << "back(): " << d.back() << std::endl;
return 0;
}
[sss@aliyun deque]$ !g++
g++ element_visit.cc -o element_visit
[sss@aliyun deque]$ ./element_visit
1 2 3 4 5
front(): 1
back(): 5
元素修改操作
函数声明 | 接口说明 |
---|
push_back()和pop_back() | deque的尾插和尾删。 |
push_front()和pop_front() | deque任意位置插入和删除。 |
insert(pos, value) | pos位置插入value。 |
erase() | 删除pos出元素。 |
swap() | 交换两个deque中的内容。 |
clear() | 将deque中的元素清空。 |
#include <iostream>
#include <deque>
void Display(const std::deque<int>& d){
for(const auto& e : d){
std::cout << e << " ";
}
std::cout << std::endl;
}
int main(){
std::deque<int> d;
Display(d);
d.push_back(0);
d.push_back(1);
d.push_front(2);
d.insert(d.begin() + 2, 3);
Display(d);
d.pop_back();
d.erase(d.begin());
Display(d);
std::deque<int> temp(d);
d.clear();
std::cout << "d: ";
Display(d);
std::cout << "temp: ";
Display(temp);
std::cout << std::endl << "after swap:" << std::endl;
d.swap(temp);
std::cout << "d: ";
Display(d);
std::cout << "temp: ";
Display(temp);
return 0;
}
[sss@aliyun deque]$ !g++
g++ modify.cc -o modify -std=c++11
[sss@aliyun deque]$ ./modify
2 0 3 1
0 3
d:
temp: 0 3
after swap:
d: 0 3
temp:
注意
#include <iostream>
#include <algorithm>
#include <deque>
int main(){
int arr[] = {
3, 5, 0, 1, 6, 9
};
std::deque<int> d(arr, arr + sizeof(arr) / sizeof(arr[0]));
std::deque<int>::iterator it = d.begin();
while(it != d.end()){
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
std::sort(d.begin(), d.end());
it = d.begin();
while(it != d.end()){
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
return 0;
}
[sss@aliyun deque]$ g++ sort.cc -o sort
[sss@aliyun deque]$ ./sort
3 5 0 1 6 9
0 1 3 5 6 9
deque中排序操作的效率是非常低的,因为deque中的元素在底层的实现上是不连续的。可以考虑将deque中的元素拷贝到一个vector中,然后排序之后,再将元素拷贝回来。
deque在序列式容器中算是比较鸡肋的存在,虽然它的野心很大,想要替代vector和list,但是呵呵。
deque最大的用处就是作为标准库中stack和queue的底层结构。