STL中deque(双端队列)是一种非常重要的结构,stack,与queue底层都是借助deque.
deque(双端队列)是一种双向开口的连续性空间,双向开口意思是可以在头尾两端做元素的插入和删除操作。deque和vector最大的差异在于deque允许常数时间内对起头端进行元素的插入或移除操作,二者在于deque没所谓的容量(capacity)观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。deque采用一块所谓的map作为主控,这里所谓的map是一小块连续的空间,其中每个元素都是指针,指向另一段较大的连续线性空间,称为缓冲区。缓冲区才是deque的存储空间主体。SGI STL允许我们指定缓冲区大小,默认值为0表示将使用512 bytes缓冲区。但是在deque在排序的时候需要借住vector,为了最高效率要将deque先完整复制到一个vector身上,将vector排序后再复制回deque.默认map_size开始大小为8个.
下面的代码从stl_deque中摘取,deque仅仅实现了构造对象,与插入数值。
deque无类型文件,引用所需要的文件
#ifndef _DEQUE_
#define _DEQUE_
#include"stl_construct.h"
#include"stl_iterator.h"
#include"type_traits.h"
#include"stl_uninitialized.h"
#include"stl_alloc.h"
#include"stl_deque.h"
#endif
stl_construct.h 构造的实现
#ifndef _STL_CONSTRUCT_H
#define _STL_CONSTRUCT_H
#include"type_traits.h"
#include<new.h>
template <class T>
inline void destroy(T* pointer)
{
pointer->~T();
}
template <class T1, class T2>
inline void construct(T1* p, const T2& value)
{
new (p) T1(value);
}
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for ( ; first < last; ++first)
destroy(&*first);
}
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type)
{}
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
#endif
stl_iterator.h 迭代器
#ifndef _STL_ITERATOR_H
#define _STL_ITERATOR_H
template <class T>
inline T* value_type(const T*)
{
return (T*)(0);
}
template <class T>
inline size_t* distance_type(const T*)
{
return (size_t*)(0);
}
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
template <class T>
inline random_access_iterator_tag iterator_category(const T*)
{
return random_access_iterator_tag();
}
#endif
type_traits.h 萃取机制
#ifndef _TYPE_TRAITS_H
#define _TYPE_TRAITS_H
struct __true_type
{};
struct __false_type
{};
template <class type>
struct __type_traits
{
typedef __true_type this_dummy_member_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
struct __type_traits<int>
{
typedef __true_type this_dummy_member_must_be_first;
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#endif
stl_uninitialized.h 未初始化的参数
#ifndef _STL_UNINITIALIZED_H
#define _STL_UNINITIALIZED_H
#include<typeinfo.h>
#include"stl_algobase.h"
template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __true_type)
{
return fill_n(first, n, x);
}
template<class ForwardIterator, class Size, class T>
ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T &x, __false_type)
{
ForwardIterator cur = first;
for(; n>0; --n, ++cur)
construct(&*cur, x);
return cur;
}
template<class ForwardIterator, class Size, class T, class T1>
ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n, const T &x, T1*)
{
cout<<"T1 = "<<typeid(T1).name()<<endl;
typedef typename __type_traits<T1>::is_POD_type is_POD;
return __uninitialized_fill_n_aux(first, n, x, is_POD());
}
template<class ForwardIterator, class Size, class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T &x)
{
return __uninitialized_fill_n(first, n, x, value_type(first));
}
///
template <class InputIterator, class ForwardIterator>
inline ForwardIterator __uninitialized_copy_aux(InputIterator first,
InputIterator last,
ForwardIterator result,
__true_type)
{
return copy(first, last, result);
}
template <class InputIterator, class ForwardIterator>
ForwardIterator __uninitialized_copy_aux(InputIterator first,
InputIterator last,
ForwardIterator result,
__false_type)
{
ForwardIterator cur = result;
for ( ; first != last; ++first, ++cur)
construct(&*cur, *first);
return cur;
}
template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator __uninitialized_copy(InputIterator first,
InputIterator last,
ForwardIterator result, T*)
{
typedef typename __type_traits<T>::is_POD_type is_POD;
return __uninitialized_copy_aux(first, last, result, is_POD());
}
template <class InputIterator, class ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first,
InputIterator last,
ForwardIterator result)
{
return __uninitialized_copy(first, last, result, value_type(result));
}
#endif
stl_alloc.h 空间配置器
#ifndef _STL_ALLOC_H
#define _STL_ALLOC_H
#if 0
#include<new>
#define __THROW_BAD_ALLOC throw bad_alloc
#else
#include<iostream.h>
#include<malloc.h>
#include<stdlib.h>
#define __THROW_BAD_ALLOC cerr<<"Out Of Memory."<<endl;exit(1)
#endif
//malloc free
template<int inst>
class __malloc_alloc_template
{
private:
static void* oom_malloc(size_t n)
{
void (*my_malloc_handler)();
void *result;
for(;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if(0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = malloc(n);
if(result)
return result;
}
}
static void* oom_realloc(void *p, size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = realloc(p, n);
if (result)
return(result);
}
}
static void(*__malloc_alloc_oom_handler)();
public:
static void* allocate(size_t n)
{
void *result = malloc(n);
if(0 == result)
result = oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t n)
{
free(p);
}
static void* reallocate(void *p, size_t old_sz, size_t new_sz)
{
void *result = realloc(p, new_sz);
if(0 == result)
result = oom_realloc(p, new_sz);
return result;
}
public:
//set_new_handler 模拟
static void(*set_malloc_handler(void(*f)()))()
{
void(*old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return old;
}
};
void(* __malloc_alloc_template<0>::__malloc_alloc_oom_handler)() = 0;
typedef __malloc_alloc_template<0> malloc_alloc;
/
enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES / __ALIGN};
template<bool threads, int inst>
class __default_alloc_template
{
public:
static void * allocate(size_t n);
static void deallocate(void *p, size_t n);
static void * reallocate(void *p, size_t old_sz, size_t new_sz);
protected:
static void * refill(size_t n);
static char* chunk_alloc(size_t size, int &nobjs);
private:
static size_t ROUND_UP(size_t bytes)
{
return ((bytes + __ALIGN-1) &~(__ALIGN-1));
}
private:
union obj
{
union obj * free_list_link;
char client_data[1];
};
private:
static size_t FREELIST_INDEX(size_t bytes)
{
return ((bytes + __ALIGN-1) / __ALIGN-1);
}
static obj* free_list[__NFREELISTS];
private:
static char * start_free;
static char * end_free;
static size_t heap_size;
};
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::start_free = 0;
template<bool threads, int inst>
char* __default_alloc_template<threads, inst>::end_free = 0;
template<bool threads, int inst>
size_t __default_alloc_template<threads, inst>::heap_size = 0;
template<bool threads, int inst>
__default_alloc_template<threads, inst>::obj*
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] =
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
template<bool threads, int inst>
void * __default_alloc_template<threads, inst>::allocate(size_t n)
{
obj ** my_free_list;
obj * result;
if(n > __MAX_BYTES)
return malloc_alloc::allocate(n);
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if(result == 0)
{
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result->free_list_link;
return result;
}
template <bool threads, int inst>
char*
__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
char * result;
size_t total_bytes = size * nobjs;
size_t bytes_left = end_free - start_free;
if (bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes;
return(result);
}
else if (bytes_left >= size)
{
nobjs = bytes_left/size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return(result);
}
else
{
size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
if (bytes_left > 0)
{
obj ** my_free_list = free_list + FREELIST_INDEX(bytes_left);
((obj *)start_free) -> free_list_link = *my_free_list;
*my_free_list = (obj *)start_free;
}
start_free = (char *)malloc(bytes_to_get);
if (0 == start_free)
{
int i;
obj ** my_free_list, *p;
for (i = size; i <= __MAX_BYTES; i += __ALIGN)
{
my_free_list = free_list + FREELIST_INDEX(i);
p = *my_free_list;
if (0 != p)
{
*my_free_list = p -> free_list_link;
start_free = (char *)p;
end_free = start_free + i;
return(chunk_alloc(size, nobjs));
}
}
end_free = 0;
start_free = (char *)malloc_alloc::allocate(bytes_to_get);
}
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return(chunk_alloc(size, nobjs));
}
}
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = 20;
char * chunk = chunk_alloc(n, nobjs);
obj ** my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i;
if (1 == nobjs) return(chunk);
my_free_list = free_list + FREELIST_INDEX(n);
result = (obj *)chunk;
*my_free_list = next_obj = (obj *)(chunk + n);
for (i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - 1 == i)
{
current_obj -> free_list_link = 0;
break;
}
else
{
current_obj -> free_list_link = next_obj;
}
}
return(result);
}
template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void *p,
size_t old_sz,
size_t new_sz)
{
void * result;
size_t copy_sz;
if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
{
return(realloc(p, new_sz));
}
if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
return(p);
result = allocate(new_sz);
copy_sz = new_sz > old_sz? old_sz : new_sz;
memcpy(result, p, copy_sz);
deallocate(p, old_sz);
return(result);
}
template <bool threads, int inst>
void __default_alloc_template<threads, inst>::deallocate(void *p, size_t n)
{
obj *q = (obj *)p;
obj ** my_free_list;
if (n > (size_t) __MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q -> free_list_link = *my_free_list;
*my_free_list = q;
}
/
#ifdef __USE_MALLOC
typedef __malloc_alloc_template<0> malloc_alloc;
typedef malloc_alloc alloc;
#else
typedef __default_alloc_template<0,0> alloc;
#endif
template<class T, class Alloc>
class simple_alloc
{
public:
static T * allocate(size_t n)
{
return 0==n ? 0 : (T*)Alloc::allocate(n * sizeof(T));
}
static T * allocate(void)
{
return (T*)Alloc::allocate(sizeof(T));
}
static void deallocate(T *p, size_t n)
{
if(0!=n)
Alloc::deallocate(p, n*sizeof(T));
}
static void deallocate(T *p)
{
Alloc::deallocate(p,sizeof(T));
}
};
#endif
stl_deque.h 双端队列的实现
#ifndef _STL_DEQUE_H
#define _STL_DEQUE_H
template<class T>
T max(T &a, T &b)
{
return a > b ? a : b;
}
size_t __deque_buf_size(size_t n, size_t sz)
{
return n!=0 ? n : (sz<512 ? size_t(512/sz) : size_t(1));
}
template<class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator
{
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef size_t difference_type;
typedef T** map_pointer;
typedef __deque_iterator self;
static size_t buffer_size()
{
return __deque_buf_size(BufSiz, sizeof(T));
}
T *cur;
T *first;
T *last;
map_pointer node; //T**node
/
__deque_iterator() : cur(0), first(0), last(0), node(0)
{}
void set_node(map_pointer new_node)
{
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
bool operator==(const self& x) const { return cur == x.cur; }
bool operator!=(const self& x) const { return !(*this == x); }
reference operator*() const { return *cur; }
self& operator++()
{
++cur;
if (cur == last)
{
set_node(node + 1);
cur = first;
}
return *this;
}
};
template<class T, class Alloc=alloc, size_t BufSiz=0>
class deque
{
public:
typedef T value_type;
typedef size_t size_type;
typedef value_type* pointer;
typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
public:
deque() : start(), finish(), map(0), map_size(0)
{
create_map_and_nodes(0);
}
public:
iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
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);
}
void push_front(const value_type& t)
{
if (start.cur != start.first)
{
construct(start.cur - 1, t);
--start.cur;
}
else
push_front_aux(t);
}
protected:
void push_back_aux(const value_type& t);
void push_front_aux(const value_type& t);
void reserve_map_at_back (size_type nodes_to_add = 1)
{
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)
{
if (nodes_to_add > start.node - map)
reallocate_map(nodes_to_add, true);
}
void reallocate_map(size_type nodes_to_add, bool add_at_front);
protected:
void create_map_and_nodes(size_type n);
static size_type initial_map_size()
{
return 8;
}
static size_type buffer_size()
{
return __deque_buf_size(BufSiz, sizeof(value_type));
}
pointer allocate_node()
{
return data_allocator::allocate(buffer_size());
}
protected:
typedef pointer* map_pointer;
typedef simple_alloc<value_type, Alloc> data_allocator;
typedef simple_alloc<pointer, Alloc> map_allocator;
protected:
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
};
template <class T, class Alloc, size_t BufSize>
void deque<T, Alloc, BufSize>::create_map_and_nodes(size_type num_elements)
{
size_type num_nodes = num_elements / buffer_size() + 1;
//map_size = max(initial_map_size(), num_nodes + 2);
map_size = initial_map_size() > (num_nodes + 2) ? 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;
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_elements % buffer_size();
}
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();
construct(finish.cur, t_copy);
finish.set_node(finish.node + 1);
finish.cur = finish.first;
}
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();
start.set_node(start.node - 1);
start.cur = start.last - 1;
construct(start.cur, t_copy);
}
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_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);
copy(start.node, finish.node + 1, new_nstart);
map_allocator::deallocate(map, map_size);
map = new_map;
map_size = new_map_size;
}
start.set_node(new_nstart);
finish.set_node(new_nstart + old_num_nodes - 1);
}
#endif
测试主函数main.cpp
void main()
{
deque<int> de;
de.push_back(1);
de.push_back(2);
de.push_front(3);
de.push_front(4); //4 3 1 2
deque<int>::iterator it = de.begin();
while(it != de.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
参考文献:《STL源码剖析》