数据结构
deque从直观上看上去是这样的,一段可两端进出的连续空间:
但其实它是分段的:
其主要结构包括中控器(map)+多个分段,其迭代器中的4个字段的作用分别为:node:指向哪个分段,first、last、cur分别指向这个分段的第一个、最后一个以及当前这个的元素。
上面map长度为8,说明map最多能维护8个分段,如果想申请更多分段,则需要扩充map。一个分段的长度默认为512bytes。
deque定义
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class deque : protected _Deque_base<_Tp, _Alloc> {
// requirements:
__STL_CLASS_REQUIRES(_Tp, _Assignable);
typedef _Deque_base<_Tp, _Alloc> _Base;
public: // 1.基础类型
typedef _Tp value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef typename _Base::allocator_type allocator_type; // 2.空间配置器
allocator_type get_allocator() const { return _Base::get_allocator(); }
public: // 3.迭代器
typedef typename _Base::iterator iterator;
typedef typename _Base::const_iterator const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION // 定义reverse_iterator
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_iterator<const_iterator, value_type, const_reference,
difference_type>
const_reverse_iterator;
typedef reverse_iterator<iterator, value_type, reference, difference_type>
reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
protected: // 4.map和buffer参数
typedef pointer* _Map_pointer; // 可以看出,map是一个二级指针
static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }
......
};
deque迭代器
deque之所以看起来是连续,主要是operator++和operator--两个运算子造成的现象,因此,而这两个操作依赖迭代器的设计。
首先,deque操作的是两端的数据,因此需要至少需要两个迭代器start和finish,在遍历deque时,还需要一个用于遍历的迭代器dealing。这三个deque_迭代器的实现如下:
template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator {
typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator;
typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
// 设置缓冲区分段大小,默认为512
static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Ptr pointer;
typedef _Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp** _Map_pointer;
typedef _Deque_iterator _Self;
_Tp* _M_cur; // 指向的分段
_Tp* _M_first; // 指向分段第一个元素
_Tp* _M_last; // 指向分段最后一个元素
_Map_pointer _M_node; // 指向map
......
};
deque的成员函数在进行操作时需要注意的地方:
- 排序时,最好将deque转换成vector排序,然后再换回来
- erase()时,如果待删除的元素靠前端,就把前端元素往后移动;否则就把后面的元素往前移
- clear()时,需要保留一个分段(初始分段就是一个分段),代码中是保留第一个分段,并析构里面的元素,内存并不释放。(内存配置和对象初始化分开的一个好处)
- map不够用时,将开辟2倍空间大小的map,旧map放置在新map的中间
stack和queue
这两个数据结构往往不称为容器,而是叫适配器,因为它们都是内含了一个deque,对功能做了一些封闭和修改得到的。它们有以下共同点:
- 都可以用list做为底层结构
- 都不提供迭代器