Ch4 序列式容器(上)
4.1 容器的概观与分类
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; }
以下是使用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一样)