अवलोकन से, आप deque
एक के रूप में सोच सकते हैंdouble-ended queue
में डेटा deque
तय आकार वेक्टर के chuncks द्वारा जमा हो जाती है, जो कर रहे हैं
द्वारा इंगित 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;
}
itter स्किप 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();
}
मान लेते हैं i_deque
कि 20 इंट तत्व हैं 0~19
जिनके चंक का आकार 8 है, और अब push_back 3 तत्व (0, 1, 2) i_deque
:
i_deque.push_back(0);
i_deque.push_back(1);
i_deque.push_back(2);
यह नीचे की तरह आंतरिक संरचना है:
फिर push_back फिर से, यह आह्वान करेगा नया हिस्सा आवंटित:
push_back(3)
यदि हम push_front
, यह प्रचलित से पहले नया हिस्सा आवंटित करेंगेstart
ध्यान दें कि जब push_back
तत्व डीके में है, यदि सभी नक्शे और विखंडन भरे हुए हैं, तो यह नए नक्शे को आवंटित करेगा, और विखंडू को समायोजित करेगा। लेकिन उपरोक्त कोड आपको समझने के लिए पर्याप्त हो सकता है deque
।