deque簡介
deque是一個雙向開口的容器,可在頭尾兩端插入和刪除元素,deque由動態的連續空間組合而成,因爲迭代器的良好設計,提供了隨機訪問,造成一種deque爲連續空間的假象
deque的數據結構
deque有一個二級指針map,map指向一小塊空間,其中的每個元素都是指針,指向一段連續線性空間,稱爲緩衝區,緩衝區爲deque存儲的主體,其中存放元素
tempalte <class T, class Alloc = alloc>
class deque {
public:
typedef T value_type;
typedef T* pointer;
typedef T** map_pointer;
protected:
iterator start;
iterator finish;
map_pointer map;
size_type size; //map內指針個數
......
}
iterator 結構如下:
template <class T>
class deque_iterator {
public:
typedef T** map_pointer;
T* cur; //指向所指緩衝區當前元素
T* first; //首元素
T* last; //尾元素後一個
map_pointer node; //指向控制中心
}
用圖表示如下
deque的主要操作
1.push_front
當start指向的緩衝區無備用空間時,執行push_front_aux
push_front_aux
操作如下:
判斷map前端的備用節點是否充足,如果充足,則再分配一個緩衝區,start.node - 1指向它,然後改節點,構造元素即可
如果map前端備用節點不足,如果map_size夠大,則並不需要重新分配map, 只需要移動map中的元素即可,最後重置start, finish迭代器
即可
如果map_size不夠大,則要重新分配map
2.push_back
操作與push_front類似
3.pop_front
void pop_front() {
if (start.cur != start.last - 1) {
//第一緩衝區有多個元素
destroy(start.cur);
++start.cur;
}
else
pop_front_aux();
}
void pop_front_aux() {
destroy(start.cur);
deallocate_node(start.first); //回收緩衝區空間
start.set_node(start.node + 1); //重置迭代器
start.cur = start.first;
}
4.pop_back
void pop_back() {
if (finish.cur != finish.first) {
//最後緩衝區有元素
--finish.cur;
destroy(finish.cur);
}
else
pop_back_aux();
}
void pop_back_aux() {
deallocate_node(finish.first); //回收緩衝區空間
finish.set_node(finish.node - 1); //重置迭代器
finish.cur = finish.last - 1;
destroy(finish.cur);
}
deque迭代器完整實現
template <class T>
class deque_iterator {
public:
typedef deque_iterator<T> iterator;
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef ptrdiff_t difference_type;
typedef T** map_pointer;
typedef deque_iterator self;
T* cur; //指向所指緩衝區當前元素
T* first; //首元素
T* last; //尾元素後一個
map_pointer node; //指向控制中心
deque_iterator():cur(0), first(0), last(0), node(0){}
deque_iterator(const deque_iterator& other):
cur(other.cur), first(other.first), last(other.last), node(other.node){}
static size_t buffer_size() {
return deque_buffer_size(sizeof(T));
}
//重新設置指向管控中心的指針,修改first, last指向緩衝區
void set_node(map_pointer new_node) {
node = new_node;
first = *new_node;
last = *new_node + (difference_type)buffer_size();
}
reference operator* () const {
return *cur;
}
pointer operator-> () const {
return &(operator*());
}
difference_type operator- (const self& x) const {
return difference_type((buffer_size() * (node - x.node - 1))
+ (cur - first) + (x.last - x.cur));
}
//前置++
self& operator++ () {
++cur;
if (cur == last) {
set_node(node + 1);
cur = first;
}
return *this;
}
//後置++
self operator++ (int) {
self temp = *this;
++*this;
return temp;
}
//前置--
self& operator-- () {
if (cur == first) {
set_node(node - 1);
cur = last;
}
--cur;
return *this;
}
//後置--
self operator-- (int) {
self temp = *this;
--*this;
return temp;
}
//實現隨機存取
self& operator+= (difference_type n) {
difference_type offset = n + cur - first;
size_t size = buffer_size();
if (offset >= 0 && offset < size)
cur += n;
else {
//不在同一緩衝區內
difference_type node_offset = offset > 0 ?
offset / size :
-difference_type((-offset - 1) / size) - 1;
//重置node,設置cur指向
set_node(node + node_offset);
cur = first + (offset - node_offset * size);//offset正負都適用
}
return *this;
}
self operator+ (difference_type n) const {
self temp = *this;
return temp += n;
}
self& operator-= (difference_type n) {
return *this += -n;
}
self operator- (difference_type n) const {
self temp = *this;
return temp -= n;
}
//重載[],隨機存取
reference operator[] (difference_type n) const {
return *(*this + n);
}
bool operator== (const self& x) { return cur == x.cur; }
bool operator!= (const self& x) { return cur != x.cur; }
bool operator< (const self& x) {
return (node == x.node) ? (cur < x.cur) : (node < x.node);
}
};
爲了將deque的迭代器使用起來看似是普通指針需要費些功夫
小結:
由deque的構造我們可以很自然的想到,用deque作爲底層容器來實現stack,queue,對於stack,queue的所有操作只需要對deque轉調用即可