deque原理简要介绍
deque(双端队列)是一种双开口的一段段连续小空间拼接而成的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)。与vector比较,头插效率高;与list比较,空间利用率比较高,随机访问效率比list好。
实际上deque类似于一个动态的二维数组,其底层结构如下图所示:
双端队列底层是一段假象的连续空间,实际是分段连续的,为了提高随机访问效率,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:
first | 指向一个buffer的开始 |
last | 指向一个buffer的结束 |
cur | 指向buffer中的一个数据 |
node | 指向存储当前buffer指针的中控位置 |
start | 指向第一个buffer,cur指向此buffer的第一个数据 |
finish | 指向最后一个buffer,cur指向此buffer的最后一个数据的下一个位置 |
deque的缺陷
随机访问
buffer大小固定
假设大小为 s,要访问下标为 i 的元素,则需要访问第 i / s 个buffer里的第 i % s 个元素,如果第一个buffer不是从头开始,也就是在随机访问前头插了 n 个元素,只需要 i -= n,然后访问第 i / s 个buffer里的第 i % s 个元素。
效率较高,但不及vector。
buffer大小非固定
需要先计算当前buffer里的数据个数,然后计算下标为 i 的元素是否在当前buffer里,不在则需要向后遍历每个buffer。
效率较低,最坏情况下效率与list相当。
中间插入删除
buffer大小固定
在下标为 i 的位置进行insert,若 i 前面的buffer已经满了,则需要将 i 后面的数据向后进行挪动。
效率较低,最坏情况下效率与vector相当。
buffer大小非固定
在下标为 i 的位置进行insert,若 i 前面的buffer已经满了,新申请一块buffer存放数据,并连接到前一个buffer后面,再将中控里后面的buffer向后进行挪动。
效率较高,但不及list。
小结
deque的随机访问和中间插入删除是互斥的两个问题,SGI版本STL里的deque采用大小固定的buffer,因此,使用deque容器时应避免中间插入删除操作,而需要大量随机访问的操作,如sort,也应换用vector容器。
总结
Vector | List | SGI-deque(固定大小buffer) | |
优点 |
|
|
|
缺点 |
|
|
|