前言:
双端队列deque看起来是一个相当牛的容器,表面看起来将list和vector进行结合起来,形成了一个看起来很完美的容器,但是事实不是这样,要是deque如此完美,数据结构也就没list和vector的事情了,数据结构早就重新洗牌了,接下来我们一起探究一下deque的奥妙
内容摘要:
本文通过 双端队列的介绍、双端队列的内部结构、迭代器机理、缺陷这几个方面进行了介绍;分析了双端队列的底层实现结构,并通过和vector、list进行对比分析,希望能够给大家带来收获。
list和vector的优缺点分析
先将vector容器和list容器的优缺点进行分析,方便后续将双端队列的底层进行分析。
对于list来说:优点是 插入删除效率高:list由一个一个节点组成,在进行插入和删除数据时只需要进挪动指针,并不需要挪动数据 。不过缺点也比较明显:只能通过指针的遍历进行元素数据的访问,不能过进行任意位置的数据访问,任意位置访问的效率相对于vector效率较低;
对于vector来说:优点是①可以进行任意位置的数据访问:在内存中空间是连续的可以通过下标进行任意位置数据的访问 ②CPU高速缓存效率高,因为CPU可以利用预取技术提前加载相邻的元素、缓存行(通常为64字节)会一次性加载一段连续的内存。缺点是①vector需要进行扩容操作,扩容操作也就意味着开辟更大的空间,有可能会造成空间的浪费。②由于vector本身结构的问题,当进行插入和删除数据时,需要进行数据的挪动,尤其是当进行头插操作时,会将容器中所有的数据都进行挪动,这是很要命的
双端队列的介绍
双端队列是一种能够进行头插、尾插、头删、尾删、任意位置插入、任意位置进行删除并且还能够进行任意位置进行遍历的队列,这里需要注意deque并不是包含在queue头文件下的,要想进行deque的使用需要包含#include<deque>。
双端队列的内部结构
双端队列即能够进行头插、尾插、头删、尾删、任意位置插入、任意位置进行删除并且还能够进行任意位置进行遍历,这是怎么做到的呢???接下来让我们来看一下双端队列的结构
注意:这里每一个数组指针进行开辟的空间大小都是相同的
双端队列deque通过创建一个指针数组,刚开始存储的指针位于数组的中间位置,中间位置也被称为中控,当想要进行头插操作时,在指针数组的中间往前的插入一个指针,通过指针进行开辟一片空间,然后在这片空间在进行如图所示的插入操作,这样就巧妙的进行了插入操作;尾插也是通过同样的技巧进行的,如果指针数组中最后一个数组指针指向的空间没有满,则在这个数组指针指向的数组的空位置进行插入,如果存放的最后一个数组指针指向的数组已满则通过指针进行开辟一片空间然后进行插入操作。
当想要进行在中间任意位置进行插入操作时,这里就有两种思路,
其一是通过数组指针进行扩容操作,然后在进行指定位位置的插入,这样的好处在于,每次进行中间任意指定位置的插入,不需要进行挪动指定位置后的全部数据,只需要挪动一个数组指针指向的数组中的一小部分数据,插入效率对于list来说还是弱势一些毕竟需要进行数据的挪动,但是相对于vector高了许多相,但是这种方式牺牲了任意位置进行访问数据的优势
其二,当需要进行中间任意位置的插入操作时,每个数组指针刚开始开辟的空间大小是不变的,通过将在指定位置以及指定位置以后的元素进行向后挪动,确保每个数组指针指向的空间位置大小是相同的,这种做法是牺牲了中间位置的插入效率来确保遍历访问的效率。SGI版本就是使用的这种确保住访问遍历效率的方式。
当进行任意的位置访问时,例如想要进行位置位置数据元素的获取时((n-3)/10)%10就能够找到n位置的元素
deque中的迭代器维护结构的机理
deque中的迭代器是通过四个指针进行实现的,cur指针是指向当前元素的位置,first是指向小数组首元素的位置,last是指向小数组最后末位元素的位置,而node指针指向指针数组中指针的位置,当迭代器通过封装这四个指针实现的迭代器。当cur在last指针之前,当迭代器指针进行++时,cur向后移动一个位置;当cur指针和last指针指向同一片位置,当迭代器指针在进行++时,node指针就需要向后移动一个位置,找到下一个小数组的位置,然后在进行更新cur、first、last的位置。
deque的缺陷
deque最大的缺陷就是不够极致
与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不 需要搬移大量的元素,因此其效率是必vector高的。 与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。
但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到 某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构 时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作 为stack和queue的底层数据结构。