개요에서, 당신은 생각할 수있는 deque
A와double-ended queue
데이터 deque
는 고정 크기 벡터의 청크에 의해 저장됩니다.
로 가리키는 map
(벡터 덩어리이기도하지만 크기가 변경 될 수 있음)
의 주요 부품 코드는 다음 deque iterator
과 같습니다.
/*
buff_size is the length of the chunk
*/
template <class T, size_t buff_size>
struct __deque_iterator{
typedef __deque_iterator<T, buff_size> iterator;
typedef T** map_pointer;
// pointer to the chunk
T* cur;
T* first; // the begin of the chunk
T* last; // the end of the chunk
//because the pointer may skip to other chunk
//so this pointer to the map
map_pointer node; // pointer to the map
}
의 주요 부품 코드는 다음 deque
과 같습니다.
/*
buff_size is the length of the chunk
*/
template<typename T, size_t buff_size = 0>
class deque{
public:
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef __deque_iterator<T, buff_size> iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
typedef pointer* map_pointer;
// allocate memory for the chunk
typedef allocator<value_type> dataAllocator;
// allocate memory for map
typedef allocator<pointer> mapAllocator;
private:
//data members
iterator start;
iterator finish;
map_pointer map;
size_type map_size;
}
아래 deque
에서는 주로 세 부분으로 된 핵심 코드를 제공합니다 .
반복자
구성하는 방법 deque
1. 반복자 ( __deque_iterator
)
반복자의 주요 문제는 ++ 일 때-반복자가 다른 청크로 건너 뛸 수 있다는 것입니다 (청크의 가장자리를 가리키는 경우). 예를 들어, 세 개의 데이터 청크가 : chunk 1
, chunk 2
, chunk 3
.
pointer1
받는 포인터의 시작 chunk 2
때 연산자 --pointer
는 말에 포인터 것이다 chunk 1
그래서에 관해서 pointer2
.
아래에서는 주요 기능을 제공합니다 __deque_iterator
.
먼저 덩어리로 건너 뜁니다.
void set_node(map_pointer new_node){
node = new_node;
first = *new_node;
last = first + chunk_size();
}
chunk_size()
청크 크기를 계산 하는 함수는 단순화를 위해 8을 반환한다고 생각할 수 있습니다.
operator*
청크로 데이터를 얻다
reference operator*()const{
return *cur;
}
operator++, --
// 증분 형태의 접두사
self& operator++(){
++cur;
if (cur == last){ //if it reach the end of the chunk
set_node(node + 1);//skip to the next chunk
cur = first;
}
return *this;
}
// postfix forms of increment
self operator++(int){
self tmp = *this;
++*this;//invoke prefix ++
return tmp;
}
self& operator--(){
if(cur == first){ // if it pointer to the begin of the chunk
set_node(node - 1);//skip to the prev chunk
cur = last;
}
--cur;
return *this;
}
self operator--(int){
self tmp = *this;
--*this;
return tmp;
}
반복자 건너 뛰기 n 단계 / 임의 액세스
self& operator+=(difference_type n){ // n can be postive or negative
difference_type offset = n + (cur - first);
if(offset >=0 && offset < difference_type(buffer_size())){
// in the same chunk
cur += n;
}else{//not in the same chunk
difference_type node_offset;
if (offset > 0){
node_offset = offset / difference_type(chunk_size());
}else{
node_offset = -((-offset - 1) / difference_type(chunk_size())) - 1 ;
}
// skip to the new chunk
set_node(node + node_offset);
// set new cur
cur = first + (offset - node_offset * chunk_size());
}
return *this;
}
// skip n steps
self operator+(difference_type n)const{
self tmp = *this;
return tmp+= n; //reuse operator +=
}
self& operator-=(difference_type n){
return *this += -n; //reuse operator +=
}
self operator-(difference_type n)const{
self tmp = *this;
return tmp -= n; //reuse operator +=
}
// random access (iterator can skip n steps)
// invoke operator + ,operator *
reference operator[](difference_type n)const{
return *(*this + n);
}
2. 건설 방법 deque
공통 기능 deque
iterator begin(){return start;}
iterator end(){return finish;}
reference front(){
//invoke __deque_iterator operator*
// return start's member *cur
return *start;
}
reference back(){
// cna't use *finish
iterator tmp = finish;
--tmp;
return *tmp; //return finish's *cur
}
reference operator[](size_type n){
//random access, use __deque_iterator operator[]
return start[n];
}
template<typename T, size_t buff_size>
deque<T, buff_size>::deque(size_t n, const value_type& value){
fill_initialize(n, value);
}
template<typename T, size_t buff_size>
void deque<T, buff_size>::fill_initialize(size_t n, const value_type& value){
// allocate memory for map and chunk
// initialize pointer
create_map_and_nodes(n);
// initialize value for the chunks
for (map_pointer cur = start.node; cur < finish.node; ++cur) {
initialized_fill_n(*cur, chunk_size(), value);
}
// the end chunk may have space node, which don't need have initialize value
initialized_fill_n(finish.first, finish.cur - finish.first, value);
}
template<typename T, size_t buff_size>
void deque<T, buff_size>::create_map_and_nodes(size_t num_elements){
// the needed map node = (elements nums / chunk length) + 1
size_type num_nodes = num_elements / chunk_size() + 1;
// map node num。min num is 8 ,max num is "needed size + 2"
map_size = std::max(8, num_nodes + 2);
// allocate map array
map = mapAllocator::allocate(map_size);
// tmp_start,tmp_finish poniters to the center range of map
map_pointer tmp_start = map + (map_size - num_nodes) / 2;
map_pointer tmp_finish = tmp_start + num_nodes - 1;
// allocate memory for the chunk pointered by map node
for (map_pointer cur = tmp_start; cur <= tmp_finish; ++cur) {
*cur = dataAllocator::allocate(chunk_size());
}
// set start and end iterator
start.set_node(tmp_start);
start.cur = start.first;
finish.set_node(tmp_finish);
finish.cur = finish.first + num_elements % chunk_size();
}
청크 크기가 8 인 i_deque
20 개의 int 요소 0~19
가 있고 이제 3 개의 요소 (0, 1, 2)를 i_deque
다음 과 같이 push_back 한다고 가정 합니다 .
i_deque.push_back(0);
i_deque.push_back(1);
i_deque.push_back(2);
아래와 같은 내부 구조입니다.
그런 다음 push_back을 다시 할당하면 새 청크 할당이 호출됩니다.
push_back(3)
만약 우리 push_front
가 prev 이전에 새로운 덩어리를 할당 할 것이다.start
참고 push_back
지도 및 청크 모두 채워진 경우 양단 큐에 요소, 그것은 새로운 맵을 할당 원인이, 당신이 이해하기 위의 코드가 충분히있을 수 있습니다 chunks.But을 조정합니다 deque
.