Ch4 序列式容器(上)

4.1 容器的概观与分类

         QQ图片20170124120513

4.2 vector

4.2.3 vector的迭代器

vector的迭代器是普通指针,属于Random Access Iterator。

template <class T, class Alloc=alloc>
class vector {
    public:
        typedef T value_type;
        typedef value_type* iterator;
    ...
};

//如: vector<int>::iterator ivite;
//         ivite的型别就是int*

 

4.2.4 vector的数据结构

为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些(大于等于,等于的时候说明满载了,再有新增元素,整个vector就需要重新malloc了):

template <class T, class Alloc = alloc>
class vector {
    ...
    protected:
        iterator start;        //表示目前使用空间的头
        iterator finish;       //表示目前使用空间的尾
        iterator end_of_storage;  //表示目前可用(含备用)空间的尾
    ...
};

运用以上三个迭代器,vector可提供以下操作:

template <class T, class Alloc = alloc>
class vector {
    ...
    public:
        iterator begin() { return start; }
        iterator end() { return finish; }
        size_type size() const { return size_type(end() - begin()); }
        size_type capacity() const {
            return size_type(end_of_storage - begin()); }
        bool empty() const { return begin() == end(); }
        reference operator[] (size_type n) { return *(begin()+n); }

        reference front() { return *begin(); }
        reference back() { return *(end()-1); }
    ...
};

4.2.5 vector的构造与内存管理:constructor,push_back

vector缺省使用alloc作为空间配置器,并据此另定义了一个data_allocator(为了方便以元素大小为配置单位):

template <class T, class Alloc = alloc>
class vector {
    protected:
        typedef simple_alloc<value_type,Alloc> data_allocator;
    ...
};

//data_allocator::allocate(n)  表示配置n个元素空间

 

vector提供了许多constructors:

//构造函数,允许指定vector大小n和初值value
vector( size_type n, const T& value) { fill_initialize(n, value); }

//填充并予以初始化
void fill_initialize( size_type n,const T& value ) {
    start = allocate_and_fill(n, value);
    finish = start +n;
    end_of_storage = finish;
}

//配置而后填充
iterator allocate_and_fill(size_type n, const T& x) {
    iterator result = data_allocator::allocate(n);  //配置n个元素空间
    uninitialized_fill_n(result, n, x);
    return result;
}

uninitialized_fill_n在2.3节

 

以下是使用push_back()将新元素插入于vector尾部时的源码:

void push_back(const T& x) {
    if( finish!= end_of_storage) {       //还有备用空间
        construct( finish, x);
        ++finish;
    }else{
        insert_aux(end(), x);     //没有备用空间,扩充空间
}

template <class T, class Alloc>
void vector<T ,Alloc>::insert_aux(iterator position, const T& x) {
    if( finish != end_of_storage) {
        //在备用空间起始处构造一个元素,并以vector最后一个元素值为其初值
        construct( finish, *(finish -1));

        ++finish;
        T x_copy=x;
        copy_backward( position, finish -2 , finish-1);
        *position =x_copy;
    }else{
        //如果原大小为0,则配置1
        //如果原大小不为0,则配置原大小的两倍
        //前半段用来放置原数据,后半段用来放置新数据
        const size_type old_size =size();
        const size_type len= old_size !=0 ? 2*old_size :1;
        
        iterator new_start =data_allocator::allocate(len);
        iterator new_finish =new_start;
        try{
            //将原vector的内容拷贝到新vector
            new_finish = uninitialized_copy(start, position, new_start);
            //将新元素设定初值x
            construct(new_finish, x);
            ++new_finish;
            //将新安插点的原内容也拷贝过来
            new_finish = uninitialized_copy(position, finish,new_finish);
        }catch(...) {
            destroy(new_start, new_finish);
            data_allocator::deallocate(new_start,len);
            throw;
        }
        //析构并释放原vector
        destroy(begin(),end());
        deallocate();
        //调整迭代器,指向新vector
        start=new_start;
        finish=new_finish;
        end_of_storage=new_start+len;
    }
}

注意:所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。

4.2.6 vector的元素操作:pop_back,erase,clear,insert

pop_back:
//把尾端元素拿掉,并调整大小
void pop_back() {
    --finish;
    destroy(finish);
}
erase:
iterator erase(iterator first, iterator last) {
    iterator i=copy(last, finish, first);
    destroy(i,finish);
    finish=finish-(last-first);
    return first;
}

iterator erase(iterator position){
    if(position+1!=end()){
        copy(position+1, finish, position);
    }
    --finish;
    destroy(finish);
    return position;
}
clear:
void clear() {
    erase(begin(), end());
}
insert:
template <class T, class Alloc>
void vector<T,Alloc>::insert(iterator position, size_type n, const T& x) {
    if(n!=0){
         if(size_type(end_of_storage - finish) >=n ) {
        //备用空间大于等于“新增元素个数”
        T x_copy=x;
        //计算位于插入点后面的现有元素个数
        const size_type elems_after=finish-position;
        iterator old_finish=finish;
        if(elems_after>n){
            //“位于插入点后面的现有元素个数”大于“新增元素个数”
            uninitialized_copy( finish-n, finish, finish);
            finish+=n;
            copy_backward(position, old_finish_n. old_finish);
            fill(position, position+n, x_copy);  //从插入点开始填入新值
        }else{
            uninitialized_fill_n(finish, n-elems_after, x_copy);
            finish+=n-elems_after;
            uninitialized_copy(position, old_finish, finish);
            finish+=elems_after;
            fill(position, old_finish,x_copy);
        }
         }else{
        //需要配置额外的内存
        const size_type old_size=size();
        const size_type len=old_size+max(old_size,n);
        //配置新的vector空间
        iterator new_start =data_allocator::allocate(len);
        iterator new_finish =new_start;
        _STL_TRY{
            //首先将旧vector的位于插入点之前的元素复制到新空间
            new_finish=uninitialized_copy(start, position, new_start);
            //再将新增元素(初值皆为x)填入新空间
            new_finish=uninitialized_fill_n(new_finish, n, x);
            //再将旧vector的位于插入点之后的元素复制到新空间
            new_finish=uninitialized_copy(position, finish, new_finish);
        }
        #ifdef __STL_USE_EXCEPTIONS
            catch(...){
                destroy(new_start, new_finish);
                data_allocator::deallocate(new_start,len);
                throw;
            }
        #endif
        //清除并释放旧的vector
        destroy(start,finish);
        deallocate();
        
        start=new_start;
        finish=new_finish;
        end_of_storage=new_start+len;
         }
    }
}

4.3 list

4.3.1 list概述

相比vector,list每次插入或删除一个元素,就配置或释放一个元素空间,因此list不会浪费空间,且对于任何位置的元素插入或元素移除,list都是常数时间。

4.3.2 list的节点

template <class T>
struct __list_node {
    typedef void* void_pointer;
    void_pointer prev;  //即 __list_node<T>*
    void_pointer next;
    T data;
}

4.3.3 list的迭代器

STL list是双向链表,故其迭代器必须具备前移、后移的能力,所以list的迭代器是Bidirectional Iterators:

template <class T, class Ref, class Ptr>
struct __list_iterator {
    typedef __list_iterator<T,T&,T*> iterator;
    typedef __list_iterator<T,Ref,Ptr> self;

    typedef bidirectional_iterator_tag iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;

    link_type node;  //指向list节点的普通指针

     //constructor
    __list_iterator(link_type x): node(x) { }
    __list_iterator() { }
    __list_iterator(const iterator& x): node(x.node) { }

    bool operator==(const self& x) const {  return node == x.node; }
    bool operator!=(const self& x) const { return node != x.node; }
    //对迭代器取值,取节点的数据值
    reference operator*() const { return (*node).data; }

    //迭代器的成员存取运算子的标准做法
     pointer operator->() const { return &(operator*()); }
    
    //对迭代器累加1,即前进一个节点
    self& operator++(){
        node=(link_type)((*node).next);
        return *this;
    }
    self operator++(int) {
        self tmp=*this;
        ++*this;
        return tmp;
    }

    //对迭代器递减1,即后退一个节点
    self& operator--(){
        node=(link_type)((*node).prev);
        return *this;
    }
    self operator--(int) {
        self tmp=*this;
        --*this;
        return tmp;
    }
}

4.3.4 list的数据结构

SGI list还是一个环状双向链表,所以它只需要一个指针,便可以完整表现整个链表:

template <class T,class Alloc = alloc>
class list {
    protected:
        typedef __list_node<T> list_node;
    public:
        typedef list_node* link_type;
    
    protected:
        link_type node;
    ...
}

如果让指针node指向刻意置于尾端的一个空白节点,node便能符合STL对于“前闭后开”区间的要求,成为last迭代器。

4.3.5 list的构造与内存管理:constructor,push_back,insert

list缺省使用alloc作为空间配置器,并据此另定义了一个list_node_allocator(为了方便以节点大小为配置单位):

template <class T, class Alloc = alloc>
class list {
    protected:
        typedef __list_node<T> list_node;
        //空间配置器,每次配置一个节点大小
        typedef simple_alloc<list_node,Alloc> list_node_allocator;
    ...
    //list_node_allocator(n) 表示配置n个节点空间

    ...
    protected:
        //配置一个节点并传回
        link_type get_node() { return list_node_allocator::allocate(); }
        //释放一个节点
        void put_node(link_type p) { list_node_allocator::deallocate(p); }

        //产生(配置并构造)一个节点,带有元素值
        link_type create_node( const T& x){
        link_type p=get_node();
        construct(&p ->data, x);
        return p;
        }
        //销毁(析构并释放)一个节点
        void destroy_node(link_type p){
        destroy(&p->data);
        put_node(p);
        }
}

 

list的default constructor:

public:
    list() { empty_initialize(); }  //产生一个空链表
    
protected:
    void empty_initialize() {
       node=get_node();  //配置一个节点空间,令node指向它
        node->next=node;  //令node头尾都指向i自己,不设元素值
        node->prev=node;
}

 

使用push_back()将新元素插入于list尾端时,函数内部调用insert:

void push_back(const T& x) { insert(end(), x); }

 

insert(),在迭代器position所指位置插入一个节点,内容为x

iterator insert(iterator position, const T& x) {
    link_type tmp=create_node(x);  //产生一个节点
    //调整双向指针,使tmp插入进去
    tmp->next=position.node;
    tmp->prev=position.node->prev;
    (link_type(position.node->prev)) ->next=tmp;
    position,node->prev=tmp;
    return tmp;
}

4.3.6 list的元素操作:push_front,push_back,erase,pop_front,pop_back,clear,remove,unique,splice,merge,reverse,sort

push_front & push_back:
void push_front(const T& x) { insert(begin(),x); }
void push_back(const T& x) { insert(end(),x); }
erase:
iterator erase(iterator position) {
    link_type next_node=link_type(position.node->next);
    link_type prev_node=link_type(position.node->prev);
    prev_node->next=next_node;
    next_node->prev=prev_node;
    destroy_node(position.node);
    return iterator(next_node);
}
pop_front & pop_back:
void pop_front() { erase(begin()); }
void pop_back() { 
    iterator tmp=end();
    erase(--tmp);
}
clear:
template <class T, class Alloc>
void list<T, Alloc>::clear(){
    link_type cur=(link_type) node->next;
    while(cur!=node){
        link_type tmp=cur;
        cur=(link_type) cur->next;
        destroy_node(tmp);
    }
    node->next=node;
    node->prev=node;
}
remove:
template <class T, class Alloc>
void list<T,Alloc>::remove(const T& value) {
    iterator first=begin();
    iterator last=end();
    while(first!=last){
        iterator next=first;
        ++next;
        if(*first==value) erase(first);  //将数值为value的元素移除
        first=next;
    }
}
unique:
//移除数值相同的连续元素
//只有"连续而相同的元素",才会被移除剩一个
template <class T, class Alloc>
void list<T,Alloc>::unique(){
    iterator first=begin();
    iterator last=end();
    if(first==last) return;

    iterator next=first;
    while(++next!=last){
        if(*first==*next) erase(next);
        else first=next;
        next=first;
    }
}
transfer:
protected:
    //将[first, last)内的所有元素移动到position前面
    void transfer(iterator position, iterator first,iterator last) {
        (*(link_type((*last.node).prev))).next=position.node;
        (*(link_type((*first.node).prev))).next=last.node;
        (*(link_type((*position.node).prev))).next=first.node;

        link_type tmp=link_type((*position.node).prev);
        (*position.node).prev=(*last.node).prev;
        (*last.node).prev=(*first.node).prev;
        (*first.node).prev=tmp;
    }
}
splice:
public:
    //1.将x接合于position所指位置之前。x必须不同于*this
    void splice(iterator position, list& x){
        if(!x.empty())
            transfer(position,x.begin(),x.end());
    }
    
    //2.将i所指元素接合于position所指位置之前。position和i可指向同一个list
    void splice(iterator position, list&,iterator i){
        iterator j=i;
        ++j;
        if(position==i || position==j) return;
        transfer(position,i,j);
    }

    //3.将[first, last)内的所有元素接合于position所指位置之前
    //   position和[first, last)可指向同一个list,
    //   但position不能位于[first, last)之内
    void splice(iterator position, list& ,iterator first, iterator last){
        if(first!=last)
           transfer(position,first,last);
   }
merge:
//合并两个list,两个list的内容必须先经过递增排序
template <class T, class Alloc>
void list<T, Alloc>::merge(list<T,Alloc>& x){
    iterator first1=begin();
    iterator last1=end();
    iterator first2=x.begin();
    iterator last2=x.end();

    while(first1!=last1 && first2!=last2) {
        if(*first2<*first1){
            iterator next=first2;
            transfer(first1,first2,++next);
            first2=next;
        }else
            ++first1;
    }
    if(first2!=last2)
        transfer(last1,first2,last2);
}
reverse:
template <class T,class Alloc>
void list<T,Alloc>::reverse(){
    if(node->next == node || link_type(node->next)->next ==node)
        return;
    iterator first=begin();
    ++first;
    while(first!=end()){
        iterator old=first;
        ++first;
        transfer(begin(), old, first);
    }
}
sort:
//由于STL算法sort()只接受RandomAccessIterator
//所以list采用自己的sort() ——是quick sort
template <class T,class Alloc>
void list<T,Alloc>::sort() {
    if(node->next ==node || link_type(node->next)->next ==node)
        return;
    list<T,Alloc> carry;
    list<T,Alloc> counter[64];
    int fill=0;
    while(!empty()){
        carry.splice(carry.begin(),*this,begin());
        int i=0;
        while(i<fill && !counter[i].empty()) {
            counter[i].merge(carry);
            carry.swap(counter[i++]);
        }
        carry.swap(counter[i]);
        if(i == fill ) ++fill;
    }
    for(int i=1;i<fill;i++)
        counter[i].merge(counter[i-1]);
    swap(counter[fill-1]);
}

4.4 deque

4.4.1 deque概述

1.deque是双向开口的连续线性空间;

2.deque允许于常数时间内对起头端进行元素的插入或移除操作(vector不能);

3.deque没有容量概念,它是动态地以分段连续空间组合而成,可以随时增加一段新的空间并链接起来,不必像vector那样配置新空间、复制元素、释放旧空间;

4.deque的迭代器复杂度很高,故尽量使用vector而非deque;

5.对deque进行排序操作,为了最高效率,可将deque先完整复制到一个vector身上,将vector排序后(STL sort算法),再复制回deque。

4.4.2 deque的中控器

deque采用一块map(不是STL的map容器)作为主控,map是一小块连续空间,其中的每个元素(称为节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区,而缓冲区才是deque的储存空间主体。

template <class T, class Alloc=alloc, size_t BufSiz=0>
//BufSiz默认值0,表示将使用512bytes缓冲区
class deque{
    public:
        typedef T value_type;
        typedef value_type* pointer;
        ...
    protected:
        //元素的指针的指针
        typedef pointer* map_pointer;
    protected:
        map_pointer map;  //指向map,map内的每个元素都是一个指针,指向一块缓冲区
        size_type map_size;  //map内可容纳多少指针
     //可见,map其实是一个T**
    ...
}

4.4.3 deque的迭代器

deque迭代器应该具备的结构:

1.能够指出分段连续空间(缓冲区)在哪里;

2.能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退时就必须跳跃至下一个或上一个缓冲区。

template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator { //未继承std::iterator
    typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
    typedef __deque_iterator<T,const T&,cosnt T*,BufSiz> const_iterator;
    static size_t buffer_size() { return __deque_buf_size(BufSiz, sizeof(T)); }

    typedef random_access_iterator_tag iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T** map_pointer;

    typedef __deque_iterator self;

    T* cur;  //此迭代器所指之缓冲区中的当前元素
    T* first;  //此迭代器所指之缓冲区中的头
    T* last;  //此迭代器所指之缓冲区中的尾((含备用空间)
    map_pointer node;  //指向管控中心(map)
    ...
}

 

决定缓冲区大小的函数buffer_size():

//如果n不为0,传回n,表示buffer_size由用户自定义
//如果n为0,表示buffer size使用默认值,那么
//    如果sz(元素大小,sizeof(value_type))小于512,传回512/sz,
//    如果sz不小于512,传回1
inline size_t __deque_buf_size(size_t n,size_t sz){
    return n!=0 ? n :(sz<512 ? size_t(512/sz) : size_t(1));
}

 

迭代器的前进后退:

void set_node(map_pointer new_node){
    node=new node;
    first= *new_node;
    last= first+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 tmp=*this;
    ++*this;
    return tmp;
}
self& operator--() {
    if(cur==first){
        set_node(node-1);
        cur=last;
    }
    --cur;
    return *this;
}
self operator--(int){  //后置式
    self tmp=*this;
    --*this;
    return tmp;
}    

//直接跳跃n个位置
self& operator+=(difference_type n){
    difference_type offset=n+(cur-first);
    if(offset>=0 && offset<difference_type(buffer_size()) )
        cur+=n;
    else{
        difference_type node_offset=
            offset>0 ? offset/difference_type(buffer_size())
                          : -difference_type((-offset-1)/buffer_size())-1;
        setnode(node+node_offset);
        cur=first+(offset-node_offset*difference_type(buffer_size()));
    }
    return *this;
}

self operator+(difference_type n) const{
    self tmp = *this;
    return tmp+=n;
}

self& operator-=(difference_type n) { return *this+= -n; }

self operator-(difference_type n) const{
    self tmp=*this;
    return tmp-=n;
}

reference operator[] (difference_type n) const { return *(*this + n); }

bool operator==(const self& x) const { return cur==x.cur; }
bool operator!=(const self& x) const { return !(*this==x); }
bool operator<(const self& x) const {
    return (node==x.node)? (cur<x.cur):(node<x.node);
}

 

4.4.4 deque的数据结构

template <class T, class Alloc=alloc, size_t BufSiz=0>
class deque{
    public:
        typedef T value_type;
        typedef value_type* pointer;
        typedef size_t size_type;
    public:
        typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
    protected:
        typedef pointer* map_pointer;
    protected:
        iterator start;
        iterator finish;

        map_pointer map;
        size_type map_size;
    ...
    public:
        iterator begin() { return start; }
        iterator end() { return finish; }

        reference operator[] (size_type n){
            return start[difference_type(n)];
        }

        reference front() { return *start; }
        reference back() {
            iterator tmp=finish;
            --tmp;
            return *tmp;
            //不用return *(finish-1);
            //因为没有定义finish-1的运算子
        }

        size_type size() const { return finish-start; }
        size_type max_size() const { return size_type(-1); }
        bool empty() const { return finish == start; }
}

4.4.5 deque的构造与内存管理:ctor,push_back,push_front

ctor:
/*deque两个专属空间配置器*/
protected:
    //每次配置一个元素大小
    typedef simple_alloc<value_type,Alloc> data_allocator;
    //每次配置一个指针大小
    typedef simple_alloc<pointer,Alloc> map_allocator;

    ...
    //ctor
    deque(int n,const value_type& value) : start(), finish(), map(0), map_size(0) {
        fill_initialize(n,value);
    }

    //fill_initialize()负责产生并安排好deque的结构
    //并将元素的初值设定妥当
    template <class T, class Alloc, size_t BufSize>
    void deque<T,Alloc,BufSize>::fill_initialize(size_type n, const value_type& value) {
        create_map_and_nodes(n);
        map_pointer cur;
        __STL_TRY{
            for(cur=start.node; cur<finish.node; ++cur)
                uninitialized_fill(finish.first, finish.cur, value);
        }catch(...){ ... }
    }
    //create_map_and_nodes()负责产生并安排好deque的结构
    template <class T, class Alloc, size_t BufSize>
    void deque<T,Alloc,BufSize>::create_map_and_nodes(size_type num_elements) {
        //需要节点数=(元素个数/每个缓冲区可容纳的元素个数)+1
        //如果刚好整除,会多配一个节点
        size_type num_nodes=num_elements/buffer_size()+1;
        
        //一个map要管理几个节点
        //最少8个,最多是“所需节点数+2”(前后各预留一个)
        map_size=max(initial_map_size(), num_nodes+2);
        map=map_allocator::allocate(map_size);

        map_pointer nstart=map+(map_size-num_nodes)/2;
        map_pointer nfinish=nstart+num_nodes-1;

        map_pointer cur;
        __STL_TRY{
            for(cur=nstart; cur<=nfinish; ++cur)
                *cur=allocate_node();
        }catch(...){ ... }

        start.set_node(nstart);
        finish.set_node(nfinish);
        start.cur=start.first;
        //cur指向前面多分配的一个节点的起始处
        finish.cur=finish.first + num_elements%buffer_size();
    }
push_back:
public:
    void push_back(const value_type& t){
        if(finish.cur!=finish.last-1){
            construct(finish.cur,t);
            ++finish.cur;
        }else
            //最后缓冲区只剩一个元素备用空间
            push_back_aux(t);
    }

    template <class T,class Alloc,size_t BufSize>
    void deque<T,Alloc,BufSize>::push_back_aux(const value_type& t){
        value_type t_copy=t;
        reserve_map_at_back();
        *(finish.node+1)=allocate_node();
        __STL_TRY{
            construct(finish.cur, t_copy);
            finish.set_node(finish.node+1);
            finish.cur=finish.first;
        }
        __STL_UNWIND(deallocate_node(*(finish.node+1)));
    }
push_front:
public:
    void push_front(const value_type& t){
        if(start.cur!=start.first){ 
            construct(start.cur-1,t);
            --start.cur;
        }else
            //第一缓冲区已无备用空间
            push_front_aux(t);
    }

    template <class T,class Alloc,size_t BufSize>
    void deque<T,Alloc,BufSize>::push_front_aux(const value_type& t){
        value_type t_copy=t;
        reserve_map_at_front();
        *(start.node-1)=allocate_node();
        __STL_TRY{
             start.set_node(start.node-1);
             start.cur=start.last-1;
             construct(start.cur, t_copy);
        }catch(...){
             start.set_node(start.node+1);
             start.cur=start.first;
             deallocate_node(*(start.node-1));
             throw;
        }
}

void reserve_map_at_back(size_type nodes_to_add=1){
    //如果map尾端的节点备用空间不足
    //符合以下条件则必须重换一个map(配置更大的,拷贝原来的,释放原来的)
    if(nodes_to_add+1>map_size-(finish.node-map))
        reallocate_map(nodes_to_add,false);
}

void reserve_map_at_front(size_type nodes_to_add=1){
    //如果map前端的节点备用空间不足
    //符合以下条件则必须重换一个map(配置更大的,拷贝原来的,释放原来的)
    if(nodes_to_add > start.node-map)
        reallocate_map(nodes_to_add,true);
}

template <class T,class Alloc, size_t BufSize>
void deque<T,Alloc,BufSize>::reallocate_map(size_type nodes_to_add, bool add_at_front){
    size_type old_num_nodes=finish.node-start.node+1;
    size_type new_num_nodes=old_num_nodes+nodes_to_add;
    
    map_pointer new_nstart;
    if(map_size > 2*new_num_nodes){
        new_nstart=map+(map_size - new_num_nodes)/2+(add_at_front ? nodes_to_add :0);
        if(new_nstart<start.node)
            copy(start.node, finish.node+1, new_nstart);
        else
            copy_backward(start.node, finish.node+1, new_nstart+old_num_nodes);
    }else{
        size_type new_map_size=map_size+max(map_size, nodes_to_add)+2;
        //配置一块空间,准备给新map使用
        map_pointer new_map=map_allocator::allocate(new_map_size);
        new_nstart=new_map+(new_map_size-new_num_nodes)/2 +(add_at_front ? nodes_to_add :0);
        //把原map内容拷贝过来
        copy(start.node, finish.node+1, new_nstart);
        //释放原map
        map_allocator::deallocate(map, map_size);
        //设定新map的起始地址与大小
        map=new_map;
        map_size=new_map_size;
    }

    start.set_node(new_nstart);
    finish.set_node(new_nstart+old_num_nodes-1);
}

 

4.4.6 deque的元素操作:pop_back,pop_front,clear,erase,insert

pop_back:
void pop_back(){
    if(finish.cur!=finish.first){
        --finish.cur;
        destroy(finish.cur);
    }else
        pop_back_aux();
}

template <class T,class Alloc, size_t BufSize>
void deque<T,Alloc,BufSize>::pop_back_aux(){
    deallocate_node(finish.first);
    finish.set_node(finish.node-1);
    finish.cur=finish.last-1;
    destroy(finish.cur);
}
pop_front:
void pop_front(){
    if(start.cur!=start.last-1){
        destroy(start.cur);
        ++start.cur;
    }else
        pop_front_aux();
}

template <class T,class Alloc, size_t BufSize>
void deque<T,Alloc,BufSize>::pop_front_aux(){
    destroy(start.cur);
    deallocate_node(start.first);
    start.set_node(start.node+1);
    start.cur=start.first;
}
clear:
//恢复到初始状态,保留一个缓冲区
template <class T,class Alloc,size_t BufSize>
void deque<T,Alloc,BufSize>::clear(){
    for(map_pointer node=start.node+1; node<finish.node; ++node){
        destroy(*node,*node+buffer_size());
        data_allocator::deallocator(*node, buffer_size());
    }
    if(start.node!=finish.node){
        destroy(start.cur, start.last);
        destroy(finish.first, finish.cur);
        data_allocator::deallocate(finish.first, buffer_size());
    }else
        destroy(start.cur, finish.cur);
    finish=start;
}
erase:
//清除pos所指元素
iterator erase(iterator pos){
    iterator next=pos;
    ++next;
    difference_type index=pos-start;
    if(index< (size() >>1)){  //index< size()/2
        copy_backward(start,pos,next);
        pop_front();
    }else{
        copy(next, finish, pos);
        pop_back();
    }
    return start+index;
}
//清除[first,last)区间内的所有元素
template <class T,class Alloc,size_t BufSize>
deque<T,Alloc,BufSize>::iterator
deque<T,Alloc,BufSize>::erase(iterator first,iterator last){
    if(first==start && last==first){  //如果清除的区间就是整个deque
        clear();
        return finish;
    }else{
        difference_type n=last-first;
        difference_type elems_before=first-start;
        if(elems_before<(size()-n)/2){  //如果前方的元素比较少
            copy_backward(start, first, last);  //向后移动前方元素(覆盖清除区间)
            iterator new_start=start+n;
            destroy(start, new_start);
            
            for(map_pointer cur=start.node; cur<new_start.node; ++cur)
                data_allocator::deallocate(*cur, buffer_size());
            start=new_start;
        }else{  //如果后方的元素比较多
            copy(last, finish, first);  //向前移动后方元素(覆盖清除区间))
            iterator new_finish=finish-n;
            destroy(new_finish, finish);
            
            for(map_pointer cur=new_finish.node; cur<=finish.node; ++cur)
                data_allocator::deallocate(*cur, buffer_size());
            finish=new_finish;
        }
        return start + elems_before;
    }
}
insert:
iterator insert(iterator position, const value_type& x){
    if(position.cur==start.cur){  //插入点是deque最前端
        push_front(x);
        return start;
    }else if(position.cur == finish.cur){  //插入点是deque最尾端
        push_back(x);
        iterator tmp=finish;
        --tmp;
        return tmp;
    }else{
        return insert_aux(position,x);
    }
}

template <class T,class Alloc, size_t BufSize>
typename deque<T,Alloc,BufSize>::iterator
deque<T,Alloc,BufSize>::insert_aux(iterator pos,const value_type x){
    difference_type index=pos-start;
    value_type x_copy=x;
    if(index<size()/2){  //插入点之前的元素个数比较少
        push_front(front());  //在最前端加入与首元素同值的元素
        iterator front1=start;
        ++front1;
        iterator front2=front1;
        ++front2;
        pos=start+index;
        iterator pos1=pos;
        ++pos1;
        copy(front2,pos1,front1);  //区间front2到pos1的元素复制到front1后面
    }else{  //插入点之后的元素个数比较少
        push_back(back());
        iterator back1=finish;
        --back1;
        iterator back2=back1;
        --back2;
        pos=start+index;
        copy(pos,back2,back1);
    }
    *pos=x_copy;  //在插入点上设定新值
    return pos;
}

 

4.5 stack

4.5.1 stack概述

stack是一种FILO数据机构,只有一个出口,stack允许新增元素(push)、移除元素(pop)、取得最顶端元素。

由于stack只有顶端元素才能被外界取用,stack不提供走访功能,故stack不能遍历、不提供迭代器。

4.5.2 stack定义完整列表

以某种既有容器作为底部结构,将其接口改变,使之符合“先进后出”的特性,形成一个stack。

而stack这种“修改某物接口,形成另一种风貌”的称为adapter(配接器),stack不被归类为container,而被归类为container adapter。

如以deque为底部结构的stack:

template <class T, class Sequence=deque<T> >
class stack{
    friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
    friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
    typedef typename Sequence::value_type value_type;
    typedef typename Sequence::size_type size_type;
    typedef typename Sequence::reference reference;
    typedef typename Sequence::const_reference const_reference;
protected:
    Sequence c;  //底层容器
public:
    bool empty() const{ return c.empty(); }
    size_type size() const { return c.size(); }
    reference top() { return c.back(); }
    const_reference top() const { return c.back(); }
    
    void push(const value_type& x) { c.push_back(x); }
    void pop() { c.pop_back(); }
};

template< <class T, class Sequence>
bool operator==(const stack<T,Sequence>& x,const stack<T,Sequence>& y){
    return x.c==y.c;
}

template< <class T, class Sequence>
bool operator<(const stack<T,Sequence>& x,const stack<T,Sequence>& y){
    return x.c<y.c;
}

 

4.5.4 以list作为stack的底层容器

#include <stack>
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;

int main(){
    stack<int, list<int> > istack;
    istack.push(1);
    istack.push(3);

    cout<<istck.size()<<endl;  //2
    cout<<istack.top()<<endl;  //3

    istack.pop();
    cout<<istack.top()<<endl;  //1
    cout<<istack.size()<<endl;  //1
}

4.6 queue

4.6.1 queue概述

对比stack,queue是FIFIO的数据结构(其他性质与stack一样)。

4.6.2 queue定义完整列表

以deque为底部结构的queue:

template <class T, class Sequence=deque<T> >
class queue{
    friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
    friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
    typedef typename Sequence::value_type value_type;
    typedef typename Sequence::size_type size_type;
    typedef typename Sequence::reference reference;
    typedef typename Sequence::const_reference const_reference;
protected:
    Sequence c;  //底层容器
public:
    bool empty() const{ return c.empty(); }
    size_type size() const { return c.size(); }

    //以下部分与stack不同
     reference front() { return c.front(); }
    const_reference front() const { return c.front(); }   
    reference back() { return c.back(); }
    const_reference back() const { return c.back(); }
    void push(const value_type& x) { c.push_back(x); }
    void pop() { c.pop_front(); }
};

template< <class T, class Sequence>
bool operator==(const stack<T,Sequence>& x,const stack<T,Sequence>& y){
    return x.c==y.c;
}

template< <class T, class Sequence>
bool operator<(const stack<T,Sequence>& x,const stack<T,Sequence>& y){
    return x.c<y.c;
}

4.6.4 以list作为queue的底层容器

(和4.5.4一样)

转载于:https://www.cnblogs.com/atmacmer/p/6344942.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值