双端队列,Double-ended queue,简称为deque是一种线性结构的一种容器;
在数据结构中出现的顺序表与链表,或者栈与队列都算是线性结构;
在结构中,它与vector相比较会相似一些;
但是在实际当中,双端队列 - deque 包含了vector与list的优点;
而deque综合了上面两者部分的优点;
为什么双端队列 - deque既能支持头尾插入删除,又能支持下标随机访问?
这应该和它的结构有关;

deque的结构类似于vector,因为和vector一样,总体的框架为一个连续的物理空间;
但是与vector不同的是vector作为类模板容器,数据类型为 T;
而在这里deque所存储的其实为一个指针;
这个指针的类型为T*;
可以理解为一个数组内存储多个小数组从而达到对每个数据进行存储;
但是在结构中的起始位置,为了能便于支持头尾插入删除,初始的buff数组所在的位置并不是在deque总体框架的开头,而是在中间;
deque的接口设置与大部分的容器都相同;

在接口设置中较为相似list;
为什么说是list与vector的结合呢,还有一点;

deque重载了operator[];
这也是它可以对数据进行随机访问的一个原因;
那么有个问题,在如此复杂的条件下是怎么进行数据的随机访问?
可以进行假设;
假设存在一个大小为100的deque对象,其中每个buff小数组的大小为10,且100个数据中有3个头插的数据,现在需要去访问它的第25个数据应该怎么进行访问;
只需要2步即可:用n减去头插的数据数个数(单独未满的
buff数组数据个数)再除以数组总大小得是第几个buff数组;
即(25-3)/10;
再用n减去头插的数据数个数(单独未满的buff数组数据个数)再除0数组总大小得是buff数组中的第几个数据;
即(25-3)%10;
从上图中可以看出,若是需要进行头删头插或者尾删尾插时,只需要控制每个buff小数组即可;
由于初始buff数组所在位置处中间位置,所以可以更好的进行插入删除;
buff的位置前再申请一块同样大小的空间即可;
buff数组已满,则需要新开一个buff小数组用于存储数据;deque中较难的是这个在中间位置的插入删除;固定buff数组大小 | 不固定buff数组大小 |
|---|---|
若是中间插入时固定buff数组大小,则在中间插入删除时需要大量的挪动数据,造成大量的开销 | 若是中间插入时不固定buff数组大小,即在每次插入删除的时候,尤其是在插入时,扩容所对应的buff数组,该方法可以优化中间插入,使得在中间插入时不需要大量的挪动数据,但是对应的缺点是无法使用/配合%的方式进行下标的随机访问; |
然而在STL的源码中所使用的方法为固定buff数组的大小,也就是抛弃了deque的中间插入删除;
在实际的应用场景中,使用到双端队列deque的场景并不多;
虽然它结合了vector的优点和list的优点,但是并没有十分的优异,换句话说就是无论是在效率上还是在有点伤都不能完全的取代vector与list;
在STL中,栈与队列所采用的方式为适配器模式,它们的模板参数为:
template
在适配器模式中的模板参数Container默认为deque,这也是双端队列中最经典的使用场景;