更多精彩內容,請關注微信公衆號:後端技術小屋node
deque deque.h stl_deque.h
deque爲雙向隊列,同時支持從隊首和隊尾插入和彈出值。其數據結構分爲兩部分,以下圖所示:c++
_M_map
, 元素類型爲——Tp*
。若是元素值不爲NULL
,則指向某個內存塊;deque中使用__nstart
(二級指針類型__Tp**
)指向第一個內存塊對應的數組元素;__nfinish
指向最後一個內存塊對應的數組元素node
)。代碼以下,_Tp
表示deque
中元素類型,_Alloc
爲內存分配器類型。_M_map_size
表示當前連續緩衝區_M_map
的長度,即最多能容納多少個node
。迭代器_M_start
指向deque
的左確界,對應隊首值。迭代器_M_finish
指向deque
的右虛界。後端
template <class _Tp, class _Alloc> class _Deque_base { ... protected: _Tp** _M_map; size_t _M_map_size; iterator _M_start; iterator _M_finish; ... }
deque的迭代器屬於random_access_iterator
, 支持隨機訪問
其中_M_cur
指向當前內存塊node
中當前值的位置,_M_first
指向當前內存塊node
的首地址,_M_last
指向當前內存塊的虛邊界數組
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; static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); } ... typedef _Tp** _Map_pointer; ... _Tp* _M_cur; _Tp* _M_first; _Tp* _M_last; _Map_pointer _M_node; _Deque_iterator(_Tp* __x, _Map_pointer __y) : _M_cur(__x), _M_first(*__y), _M_last(*__y + _S_buffer_size()), _M_node(__y) {}
迭代器的構造函數中,傳入queue中_M_map
中元素地址__y
,和指向內存塊node
中值的地址__x
,初始化_M_cur
, _M_first
, _M_last
和_M_node
。微信
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; static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); } ... typedef _Tp** _Map_pointer; ... _Tp* _M_cur; _Tp* _M_first; _Tp* _M_last; _Map_pointer _M_node; _Deque_iterator(_Tp* __x, _Map_pointer __y) : _M_cur(__x), _M_first(*__y), _M_last(*__y + _S_buffer_size()), _M_node(__y) {}
首先判斷迭代器當前位置是否爲node
尾部,若是是,則跳轉至右相鄰node
頭部,不然_M_cur
自增1數據結構
代碼以下,其中_M_set_node
從新指定iterator
當前內存塊爲_M_node+1
,重置_M_first
和_M_last
dom
_Self& operator++() { ++_M_cur; if (_M_cur == _M_last) { _M_set_node(_M_node + 1); _M_cur = _M_first; } return *this; } void _M_set_node(_Map_pointer __new_node) { _M_node = __new_node; _M_first = *__new_node; _M_last = _M_first + difference_type(_S_buffer_size());
首先判斷迭代器當前位置是否在當前node
頭部,若是是,則跳轉至左相鄰node
的頭部,不然_M_curr
自減1函數
_Self& operator--() { if (_M_cur == _M_first) { _M_set_node(_M_node - 1); _M_cur = _M_last; } --_M_cur; return *this; }
計算目標位置相對於本node
頭部的偏移量,判斷:源碼分析
node
大小,說明目標位置在本node
內,_M_curr
自增n
node
大小,說明目標位置不在本node
內,分別計算node
偏移量和_M_curr
偏移量,並更新iterator狀態_Self& operator+=(difference_type __n) { difference_type __offset = __n + (_M_cur - _M_first); if (__offset >= 0 && __offset < difference_type(_S_buffer_size())) _M_cur += __n; else { difference_type __node_offset = __offset > 0 ? __offset / difference_type(_S_buffer_size()) : -difference_type((-__offset - 1) / _S_buffer_size()) - 1; _M_set_node(_M_node + __node_offset); _M_cur = _M_first + (__offset - __node_offset * difference_type(_S_buffer_size())); } return *this; }
pop_front
在隊列頭部壓入值, pop_back
在隊列尾部壓入值。push_front和push_back是對稱操做,區別只在於方向不一樣。流程以下性能
執行時分爲如下幾種狀況:
node
中是否有可用空間,若是是,則直接用於容納新值,不然走2.
3.
2.
; 不然走4.
node
到新map, 繼續走2.
void push_back(const value_type& __t) { if (_M_finish._M_cur != _M_finish._M_last - 1) { construct(_M_finish._M_cur, __t); ++_M_finish._M_cur; } else _M_push_back_aux(__t); } template <class _Tp, class _Alloc> void deque<_Tp,_Alloc>::_M_push_back_aux() { _M_reserve_map_at_back(); *(_M_finish._M_node + 1) = _M_allocate_node(); __STL_TRY { construct(_M_finish._M_cur); _M_finish._M_set_node(_M_finish._M_node + 1); _M_finish._M_cur = _M_finish._M_first; } __STL_UNWIND(_M_deallocate_node(*(_M_finish._M_node + 1))); }
pop_front
在隊列頭部彈出值, pop_back
在隊列尾部彈出值。
分兩種狀況:
_M_start
或者_M_finish
以後仍在原node內,析構對象便可。_M_start
或者_M_finish
以後不在原node內,不只要析構對象,還要釋放nodevoid pop_back() { if (_M_finish._M_cur != _M_finish._M_first) { --_M_finish._M_cur; destroy(_M_finish._M_cur); } else _M_pop_back_aux(); } // Called only if _M_finish._M_cur == _M_finish._M_first. template <class _Tp, class _Alloc> void deque<_Tp,_Alloc>::_M_pop_back_aux() { _M_deallocate_node(_M_finish._M_first); _M_finish._M_set_node(_M_finish._M_node - 1); _M_finish._M_cur = _M_finish._M_last - 1; destroy(_M_finish._M_cur);
分三種狀況:
push_front
push_back
push_front(front())
, deque map前半部分左移,插入位置上構造對象。push_back(back())
, deque map後半部分右移,插入位置上構造對象iterator insert(iterator position, const value_type& __x) { if (position._M_cur == _M_start._M_cur) { push_front(__x); return _M_start; } else if (position._M_cur == _M_finish._M_cur) { push_back(__x); iterator __tmp = _M_finish; --__tmp; return __tmp; } else { return _M_insert_aux(position, __x); } }
判斷擦除位置pos在前半部分仍是後半部分
pop_front
pop_back
iterator erase(iterator __pos) { iterator __next = __pos; ++__next; difference_type __index = __pos - _M_start; if (size_type(__index) < (this->size() >> 1)) { copy_backward(_M_start, __pos, __next); pop_front(); } else { copy(__next, _M_finish, __pos); pop_back(); } return _M_start + __index; }
vector
, 由於索引到值的映射須要基於deque map進行計算。_Tp
對象的copy
操做。由於insert
和erase
使用了push(pop)_front(back)``, 所以極端條件下,也會出現
1.`中的狀況。queue
和stack
中缺省底層數據結構是deque
template <class _Tp, class _Sequence __STL_DEPENDENT_DEFAULT_TMPL(deque<_Tp>) > class queue; template <class _Tp, class _Sequence __STL_DEPENDENT_DEFAULT_TMPL(deque<_Tp>) > class stack;
固然你也能夠本身實現支持front() back() push_front() pop_front() push_back() pop_back()
等接口的_Sequence
容器,不過建議仍是用默認設置,除非能保證你實現的_Sequence
在性能可以超過deque
queue
等效於隱藏了接口push_front
和pop_back
的deque
, 而stack
等效於隱藏了接口push_front
和pop_front
的deque
。 僅此而已,因此要研究queue
和stack
的實現,最關鍵的仍是弄清楚deque
推薦閱讀
更多精彩內容,請掃碼關注微信公衆號:後端技術小屋。若是以爲文章對你有幫助的話,請多多分享、轉發、在看。