zoukankan      html  css  js  c++  java
  • 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一样)

  • 相关阅读:
    Python实现ftp服务(1)
    MYSQL/HIVESQL笔试题(六):HIVESQL(六)
    Hive基础(16):Hive函数(8) 常用函数
    MYSQL/HIVESQL笔试题(五):HIVESQL(五)
    MYSQL/HIVESQL笔试题(四):HIVESQL(四)
    MYSQL/HIVESQL笔试题(三):HIVESQL(三)
    498. Diagonal Traverse
    493. Reverse Pairs
    1021. Remove Outermost Parentheses
    490. The Maze
  • 原文地址:https://www.cnblogs.com/atmacmer/p/6344942.html
Copyright © 2011-2022 走看看