deque类
基础介绍
deque
是双端队列,它提供了和vector
类似的接口但是底层的实现与vector
完全不同,vector
底层用三个指针指向数组的起点,尾部和总容量的尾部,并且所有元素都是连续的,但是在deque
中所有元素并不一定都是在连续的内存空间上的。deque
在底层实现上是将一个连续的空间分段进行管理,并将它们的首地址用一个指针数组进行管理,这样特殊的存储结构使得它在头部和尾部增加元素比vector
更加高效,但是底层实现更为复杂,存储了很多额外信息。如果抛去在头部和尾部增加元素,在中间任意位置添加元素,它的效率比vector更高,但是比list要低。
常用接口
构造函数
1 | deque(); //构造空的双端队列 |
迭代器相关
由于deque
在内存上并不完全是连续的因此想要保持deque的连续性,这个任务就落到了迭代器身上。在底层实现上,deque
将一段一段连续的内存称为一个缓冲区(buffer),并将这些缓冲区的首尾地址存储在一个map中用以映射,map中一个存储缓冲区的地址对应一个结点(node)信息用于标记这个键值对,这样就构建好了基础架构。在迭代器中存储了4个信息,分别是当前结点(cur),当前缓冲区的头(first),当前缓冲区的尾(last)以及在map中用以标记当前缓冲区的地址的结点(node)信息。并且在deque
内部已经存储好了两个迭代器start
和finish
用于标记deque
的头和尾元素。这样即可完成将一段一段连续的空间在逻辑结构上构成一段连续空间的目的。
当从头遍历deque
时,start
迭代器中first
和last
已经从map中找到了第一个结点的缓冲区首尾信息并进行了保存,于是cur
就从first
开始遍历这个缓冲区,当遍历到last
时就重新到map中寻找写一个结点的缓冲区收尾地址并且替换掉原来first
和last
值,继续遍历,这样即可完成遍历直到最后一个结点也遍历完。1
2
3
4
5
6
7
8iterator begin(); //返回deque起始位置迭代器
iterator end(); //返回deque最后一个元素下一个位置的迭代器
reverse_iterator rbegin(); //返回deque起始位置的反向迭代器(即end())
reverse_iterator rend(); //返回deque最后一个元素下一个位置的反向迭代器(begin())
const_iterator cbegin() const; //返回deque起始位置的const迭代器
const_iterator cend() const; //返回deque最后一个元素下一个位置的const迭代器
const_reverse_iterator crbegin() const; //返回deque起始位置的const反向迭代器(即crend())
const_reverse_iterator crend() const; //返回deque最后一个元素下一个位置的const反向迭代器(crbegin())
容量相关
1 | size_type size() const; //返回deque中有效元素个数 |
增删改查
1 | reference operator[](size_type n); //返回deque中n位置上元素的引用 |
综合运用
1 | #include <iostream> |
总结
双端队列deque
是一个设计并不算成功的容器,如果要随机访问单纯的查询多一点可以用vector
而且更加方便,如果需要频繁插入那么list
效率又会跟高,因此deque
并不常用,其最常用的地方就是在作为适配器stack
和queue
的底层存储容器。