STL:deque
Posted 小键233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL:deque相关的知识,希望对你有一定的参考价值。
隔了好多天,终于把这个deque 给写了。
deque 是双端队列。也就是,方便在队头和队尾插入数据的队列。
它能够解决vector 增加元素时不停地重新分配内存和在头部插入效率低下的问题。
看到它的数据结构才觉得真心厉害。
数据结构
看图
deque的数据组织是这样的:
有一块连续的小内存充当中控器,指向真正的数据缓冲区。有点像一本书的目录。
而数据,真正是存储在缓冲区的。
deque 主要是维护好中控器和数据的关系。
我曾经考虑,也许可以使用链表来组织这个关系,就是一块一块的缓冲区通过链表连起来。
但这样设计的问题,显而易见。理想的组织方式是把deque 封装成数组,如果用链表的话,就比较难伪装空间连续的概念。
它高明的地方就在于,把中控器当作连续的空间管理,减少了直接管理大块内存的消耗,只需要维护一个连续的小空间的中控器就行
然后在这个上面伪装成空间连续的线性表。
deque 还是比较复杂的,实现的代码超千行了。
迭代器
通过上图,也可以看到迭代器的数据结构了,数据结构中,也遵循着STL 的默认规则,即缓冲区大小是[fist, last)
比较重要的一个功能是,如何把迭代器伪装成原生的指针。因为deque 的本意是双向连续的线性数组,那么它的迭代器就是 random_iterator
。
这主要归功于几个重载运算符的功劳了。
template<typename T, typename Ref, typename Ptr, size_t Buff_size>
struct _deque_iterator
typedef _deque_iterator<T, T&, T*, Buff_size> iterator;
typedef _deque_iterator<T, const T&, const T*, Buff_size> const_iterator;
typedef _deque_iterator self;
static size_t buffer_size()
return _deque_buf_size(Buff_size, sizeof(T) );
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T** map_pointer;
typedef random_access_iterator_tag iterator_category;
pointer curr;
pointer first;
pointer last;
map_pointer node;
void set_node(map_pointer new_node)
node = new_node;
first = *node;
last = first + buffer_size();
//-----------------function -------------
_deque_iterator() : curr(0), first(0), last(0), node(0)
_deque_iterator(pointer x, map_pointer y): node(y), first(*y), last(*y + buffer_size()), curr(x)
_deque_iterator(const iterator& x): curr(x.curr), first(x.first), last(x.last), node(x.node)
...
一部分的代码如此。
我们可以看看它的重载运算符是怎么样的:
difference_type operator - (const self& x) const
//这个计算公式非常巧妙,值得推敲一番
return difference_type( (node-x.node-1)*buffer_size() + (curr - first) + (x.last - x.curr) );
self& operator += (difference_type dist)
difference_type offset = dist + (curr - first);
if(offset >=0 && offset < difference_type(buffer_size() ))
curr += dist;
else
//这个计算公式.....有点厉害,我承认我写的代码是垃圾=_=
difference_type node_offset = offset >0 ? offset / difference_type(buffer_size() )
: -difference_type( (-offset - 1)/buffer_size()) -1;
set_node(node + node_offset);
curr = first + (offset - node_offset * difference_type(buffer_size()) );
return *this;
注意到我备注的几个公式,那是真厉害。
它通过一些运算,而规避了繁复的判断。
一些默认的行为
deque 的声明如下:
template<typename T, typename Alloc = alloc, size_t Buff_size = 0>
class deque;
它接受三个参数,其中第三个参数是指定了deque 的buffer 大小的,计算的函数如下:
/** _deque_buf_size 决定缓冲区大小的函数
@param n 模板中的参数
@param sz sizeof(T)
*/
inline size_t _deque_buf_size(size_t n, size_t sz)
return n!=0 ? n : (sz <512 ? size_t(512/sz) : size_t(1) );
还有,中控器的默认大小是8
剩下的都不怎么想写了, 反正接口规范就是C++ 官网的那些,对着实现功能就好了。
重要的是,数据组织的思想吧,一些设计上的细节也值得考究一下的。
惯例,代码在github 上,欢迎一起探讨问题。。。
–END–
以上是关于STL:deque的主要内容,如果未能解决你的问题,请参考以下文章