STL之deque
程序员文章站
2024-02-12 22:15:46
...
deque概述
deque是一种双向的连续性空间。所谓双向开口,意思是可以在头尾两端分别做元素的插入操作。
deque采用一块所谓的map作为主控。这里的所谓map是一块连续空间,其中每个元素都是指针,指向另一段(较大)连续空间,称为缓冲区,缓冲区才是deque的储存空间主体。
template<class T,class Alloc=alloc,size_t Buffsiz=0>
class deque{
public:
typedef T value_type;
typedef value_type* pointer;
protect:
typedef pointer* map_pointer;
map_pointer map;
size_type map_size;
};
deque的迭代器
deque是分段连续空间,维持其“整体连续”的任务,落在了迭代器operator++和operator–两个运算子上了。
其迭代器应该具有几个功能。首先,它必须能够指出分段连续空间(即缓冲区)在哪,其次它必须能够判断自己是否已经处于其所在缓冲区的边缘,如果是,一旦前进或后退时就必须跳跃到上一个或下一个缓冲区,为了能够正确跳跃,deque必须随时掌控map。
template<class T,class Ref,class Ptr,size_t Bufsiz>
struct _deque_iterator{
typedef _deque_iterator<T,T&,T*.Bufsiz> iterator;
typedef _deque_iterator<T,const T&,const 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;
T* cur//此迭代器所指缓冲区中的现行元素.
T* first//缓冲区的头
T* last//缓冲区的尾部
map_pointer map
};
/*其中用来决定缓冲区大小的函数buffer_size(),调用_deque_buf_size(),后者是一个全局函数。定义如下
如果n不为0,传回n,表示buffersize由用户定义
如果为0,表示使用buffsiz默认值,那么
如果sz(元素大小)小于512,传回512/sz。
如果sz不小于512传回1
*/
inline size_t _deque_buf_size(size_t n,size_t st){
return n!=0?n:(sz<512?size_t(512/sz):size_t(1));
}
下图是deque的中控器,缓冲区和迭代器的关系
下面是deque迭代器几个关键行为,由于迭代器内对各个指针运算都进行了重载操作,所以各个指针运算都不能直观观之。其中最关键的就是:一旦进行时遇到缓冲区边界,要特别当心,视前进或者后退而定,可能需要set_node跳一个缓冲区
void set_node(map_pointer new_node){
node=new_node;
first=*new_node;
last=first+difference(buffer_size());
}
//以下各个重载算子是迭代器运算成功的关键
reference operator*(){return *cur;}
pointer operator->(return &(operator*());)
difference_type operator-(const self& x)const{
return difference_type(buffer_size())*(node-node.x-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;
}
//以下实现随机存储,迭代器可以直接跳跃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;
set_node(node_offset);
cur=first+(offset-node_offset*(difference_type(Buffer_size())));
}
return *this;
}
self operator+(difference_type n){
self temp=*this;
return temp+=n;
}
self& operator-=(difference_type n){return *this+=-n;}
self operator-(difference_type n){
self temp=*this;
return temp-=n;
}
reference operator[](difference_type n){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);}
deque的数据结构
deque除了维护map的指针外,也维护start,finish两个迭代器,分别指向第一个缓冲区的第一个元素和最后一个缓冲区的最后一个元素,此外它当然也必须记住目前的map大小,因为一旦map所提供的节点不足,就必须重新配置一个更大的map.
template<class T,class Alloc=alloc,size_T buffsz=0>
class deque{
.............
protect:
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 temp=finish;
--temp;
return *temp;
}
size_type size()const{return finish-start;}
size_type max_size()const{return size_type(-1);}
bool empty()const{return finish==start;}
};
deque的构造和内存管理
deque有两个专属的空间配置
protected:
typdef simple_alloc<value_type,Alloc> data_allocator;
typdef simple_alloc<pointer,Alloc> map_allocator;
deque(size_type 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 bufsz>
void deque<T,Alloc,bufsz>::fill_initialize(size_t n,value_type value){
create_map_and_nodes(n);
map_pointer map;
for(cur=start.node;cur<finish.node;++cur)
uninitialize_fill(*cur,*cur+buffsize(),value);
uninitialize_fill(finish.first,finish.cur,value);
}
template<class T,class Alloc,size_T bufsz>
void deque<T,Alloc,bufsz>::create_map_and_nodes(size_type num){
size_type num_nodes=num/buffer_size()+1;
map_size=max(initial_map_size(),num_nodes+2);
map=map_allocator::allocate(map_size);
//以下令nstart和nfinish指向map所拥有全部节点的最*段
map_pointer nstart=map+(map_size-num_nodes)/2;
map_pointer nfinish=nstart+num_nodes-1;
map_pointer cur;
for(cur=nstart;cur<=nfinish;++cur)
*cur=allocate_node();
start.set_node(nstart);
finish_set_node(nfinish);
start.cur=start.first;
finish.cur=finish.first+num%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 bufsz>
void deque<T,Alloc,bufsz>::push_back_aux(const value_type &t){
value_type t_copy=t;
reserve_map_at_back();//符合某种条件必须重换一个map;
*(finish.node+1)=allocate_node();
construct(finish.cur,t_copy);
finish.set_node(finish+1);
finish.cur=finish.first;
}
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 bufsz>
void deque<T,Alloc,bufsz>::push_front_aux(const value_type &t){
value_type t_copy=t;
reserve_map_at_front();//符合某种条件必须重换一个map;
*(start.node-1)=allocate_node();
start.set_node(start.node-1);
start.cur=start.last-1;
construct(start.cur,t_copy);
}
void reserve_map_at_back(size_type node_to_add=1){
if(node_to_add+1>map_size-(finish.node-map)){
reallocate_map(nodes_to_add,false);
}
}
void reserve_map_at_front(size_type node_to_add=1){
if(node_to_add+1>start.node-map)
reallocate_map(node_to_add,true);
}
template<class T,class Alloc,size_T bufsz>
void deque<T,Alloc,bufsz>::reallocate_map(size_type node_to_add,bool add_at_front){
size_type old_num_node=finish.node-start.node+1;
size_type new_num_node=old_num_node+node_to_add;
map_pointer new_start;
if(map_size>2*new_num_node){
new_start=map+(map_size-new_num_node)/2+(add_at_front?node_to_add:0);
if(new_start<start.node)
copy(start.node,finish.node+1,new_start);
else
copy_backward(start.node,finish.node+1,new_start+old_num_nodes);
}
else{
size_type new_map_size=map_size+max(map_size,node_to_add)+2;
map_pointer new_map=map_allocate::allocate(new_map_size);
new_start=new_map+(map_size-new_num_node)/2+(add_at_front?node_to_add:0);
copy(start.node,finish.node+1,new_start);
map_allocate::deallocate(map,map_size);
map=new_map;
map_size=new_map_size;
}
start.set_node(new_start);
finish.set_node(new_start+old_num_node-1);
}
deque的元素操作
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 bufsz>
void deque<T,Alloc,bufsz>::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 bufsz>
void deque<T,Alloc,bufsz>::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::deallocate(*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
//清除某个元素
iterator erase(iterator pos)
{
iterator next = pos;
++next;
// 清除点之前的元素个数
difference_type index = pos - start;
// 如果清除点之前的元素个数比较少, 哪部分少就移动哪部分
if (index < (size() >> 1))
{
// 就移动清除点之前的元素
copy_backward(start, pos, next);
pop_front(); // 移动完毕,最前一个元素冗余,去除之
}
else // 如果清除点之后的元素个数比较少
{
copy(next, finish, pos); // 就移动清除点之后的元素
pop_back(); // 移动完毕,最后一个元素冗余,去除之
}
return start + index;
}
//清除区间元素
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 == finish) // 如果清除区间是整个deque
{
clear(); // 直接调用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; // 标记deque的新起点
destroy(start, new_start); // 移动完毕,将冗余的元素析构
// 以下将冗余的缓冲区释放
for (map_pointer cur = start.node; cur < new_start.node; ++cur)
data_allocator::deallocate(*cur, buffer_size());
start = new_start; // 设定deque的新起点
}
else // 如果清除区间后方的元素个数比较少
{
copy(last, finish, first); // 向前移动后方元素(覆盖清除区间)
iterator new_finish = finish - n; // 标记deque的新尾点
destroy(new_finish, finish); // 移动完毕,将冗余的元素析构
// 以下将冗余的缓冲区释放
for (map_pointer cur = new_finish.node + 1; cur <= finish.node; ++cur)
data_allocator::deallocate(*cur, buffer_size());
finish = new_finish; // 设定deque的新尾点
}
return start + elems_before;
}
}
insert
iterator insert(iterator position, const value_type& x)
{
// 如果是在deque的最前端插入, 那么直接push_front()即可
if (position.cur == start.cur)
{
push_front(x);
return start;
}
// 如果是在deque的末尾插入, 直接调用push_back()
else if (position.cur == finish.cur)
{
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); // 元素移动
}
else // 插入点之后的元素个数比较少
{
push_back(back()); // 在最尾端加入与最后元素同值的元素
iterator back1 = finish; // 以下标示记号,然后进行元素移动
--back1;
iterator back2 = back1;
--back2;
pos = start + index;
copy_backward(pos, back2, back1); // 元素移动
}
*pos = x_copy; // 在插入点上设定新值
return pos;
}