STL源码剖析——deque的实现

来源:互联网 发布:圣火名尊法器进阶数据 编辑:程序博客网 时间:2024/06/07 02:17

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转调用即可

原创粉丝点击