STL源碼剖析——deque的實現

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轉調用即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章