容器Deque
内存中是分段连续的缓冲区buffer,每次扩充时,扩充一个固定的 buffer 大小。
Deque的first指针指向一个buffer中的头,last指向同一个buffer的尾,node告诉控制中心map(vector实现,可不是map容器哦)的位置,cur指向当前元素,会随着++或者--变化。当然,如果跳到下一缓冲区,first和last自然也会变。另外还有两个start,finish迭代器分别指向头和尾。
map里指向的还是一串指针,因此map_pointer类型是T**。
模板参数中的 BufSiz 是指每个 buffer 容纳的元素个数,可自定。默认为0时,根据 sz[ sizeof(value_type) ] 的大小,
if sz < 512 则 buffersize = 512 / sz else buffersize = 1
控制中心 map 是一个指针 指向一个指针的数组 vector ,其扩充时也是两倍成长,每次扩充后 copy 原有元素到新内存的中段,时前部和后部后空出,以便于增加 map 中 node 时的操作。
没有自己的sort方法,因此只能用::sort() STL模板函数。
template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
typedef random_acess_iterator_tag iterator_category;
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 __dequr_iterator self;
T* cur;
T* first;
T* last;
map_pointer node; //指向map中的元素,即是一个指向指针的指针
....
};
在队列前后入队出队时,迭代器指向边界时,会自动修正++与--所指向的地址,有能力跳到下一个缓冲区,以保证表面上看是连续的。
Deque的高明之处:deque<T>::insert()
选择较短的一段在最前端或者最尾端插入一个元素,然后再元素搬移,再对空的安插点设定新值。
deque如何模拟连续空间
主要实现思想就是定义迭代器的 + - = 等操作,要求能够检查边界,跳到另一个缓存区去。
operator- 去算start和finish之间夹了多少个元素=(node-x.node-1)*diffrence_type(bufsize)+cur-first+x.last-x.cur
++ 与 -- 的实现,基本都是由 后 ++ 调用 前 ++ ,后 -- 调用 前 -- 。
这里++不需要先判断的原因是因为last可以指向尾后指针,而first没有。
deque的指针是一种随机访问指针,所以应该支持 +n 操作,重载 += 与 + 操作。-= 可以利用 += 代码实现。
self& operator-= (difference_type n)
{ return *this += -n; }
self operator- (difference_type n) const
{
self tmp = *this;
return tmp -= n;
}
reference operator[] (difference_type n) const
{ return *(*this + n); }
容器queue和stack
- queue 和 stack 都是基于 deque 实现,(内含一个deque,并限制某些操作)技术上本质为容器适配器。
- 因为只能先进先出或者先进后出,不允许遍历,所以不提供迭代器。 (声明 iterator 时会报错)否则放元素就会破坏这个特性。
其中数据为默认类型为 deque 的容器 c,所有的对 queue 和 stack 的操作都是转调用 c 的类方法去做。
本质上能完成这些转调用方法的容器都可以作为底层容器去实现 queue 】
queue不可以选择vector作为底部支撑的原因是因为vector没有pop。当然如果程序不会调用这个pop的话,编译自然也可以通过。
list 和 deque 都可以作为底层容器实现 stack 和 queue。
stack 可以选择 vector 作为底层结构,queue 不可选择 vector 作为底层结构。