Vector:
#include<iostream> using namespace std; #include<memory.h> // alloc是SGI STL的空间配置器 template <class T, class Alloc = alloc> class vector { public: // vector的嵌套类型定义,typedefs用于提供iterator_traits<I>支持 typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; typedef size_t size_type; typedef ptrdiff_t difference_type; protected: // 这个提供STL标准的allocator接口 typedef simple_alloc <value_type, Alloc> data_allocator; iterator start; // 表示目前使用空间的头 iterator finish; // 表示目前使用空间的尾 iterator end_of_storage; // 表示实际分配内存空间的尾 void insert_aux(iterator position, const T& x); // 释放分配的内存空间 void deallocate() { // 由于使用的是data_allocator进行内存空间的分配, // 所以需要同样使用data_allocator::deallocate()进行释放 // 如果直接释放, 对于data_allocator内部使用内存池的版本 // 就会发生错误 if (start) data_allocator::deallocate(start, end_of_storage - start); } void fill_initialize(size_type n, const T& value) { start = allocate_and_fill(n, value); finish = start + n; // 设置当前使用内存空间的结束点 // 构造阶段, 此实作不多分配内存, // 所以要设置内存空间结束点和, 已经使用的内存空间结束点相同 end_of_storage = finish; } public: // 获取几种迭代器 iterator begin() { return start; } iterator end() { return finish; } // 返回当前对象个数 size_type size() const { return size_type(end() - begin()); } size_type max_size() const { return size_type(-1) / sizeof(T); } // 返回重新分配内存前最多能存储的对象个数 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); } // 本实作中默认构造出的vector不分配内存空间 vector() : start(0), finish(0), end_of_storage(0) {} vector(size_type n, const T& value) { fill_initialize(n, value); } vector(int n, const T& value) { fill_initialize(n, value); } vector(long n, const T& value) { fill_initialize(n, value); } // 需要对象提供默认构造函数 explicit vector(size_type n) { fill_initialize(n, T()); } vector(const vector<T, Alloc>& x) { start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end()); finish = start + (x.end() - x.begin()); end_of_storage = finish; } ~vector() { // 析构对象 destroy(start, finish); // 释放内存 deallocate(); } vector<T, Alloc>& operator=(const vector<T, Alloc>& x); // 提供访问函数 reference front() { return *begin(); } reference back() { return *(end() - 1); } //////////////////////////////////////////////////////////////////////////////// // 向容器尾追加一个元素, 可能导致内存重新分配 //////////////////////////////////////////////////////////////////////////////// // push_back(const T& x) // | // |---------------- 容量已满? // | // ---------------------------- // No | | Yes // | | // ↓ ↓ // construct(finish, x); insert_aux(end(), x); // ++finish; | // |------ 内存不足, 重新分配 // | 大小为原来的2倍 // new_finish = data_allocator::allocate(len); <stl_alloc.h> // uninitialized_copy(start, position, new_start); <stl_uninitialized.h> // construct(new_finish, x); <stl_construct.h> // ++new_finish; // uninitialized_copy(position, finish, new_finish); <stl_uninitialized.h> //////////////////////////////////////////////////////////////////////////////// void push_back(const T& x) { // 内存满足条件则直接追加元素, 否则需要重新分配内存空间 if (finish != end_of_storage) { construct(finish, x); ++finish; } else insert_aux(end(), x); } //////////////////////////////////////////////////////////////////////////////// // 在指定位置插入元素 //////////////////////////////////////////////////////////////////////////////// // insert(iterator position, const T& x) // | // |------------ 容量是否足够 && 是否是end()? // | // ------------------------------------------- // No | | Yes // | | // ↓ ↓ // insert_aux(position, x); construct(finish, x); // | ++finish; // |-------- 容量是否够用? // | // -------------------------------------------------- // Yes | | No // | | // ↓ | // construct(finish, *(finish - 1)); | // ++finish; | // T x_copy = x; | // copy_backward(position, finish - 2, finish - 1); | // *position = x_copy; | // ↓ // data_allocator::allocate(len); <stl_alloc.h> // uninitialized_copy(start, position, new_start); <stl_uninitialized.h> // construct(new_finish, x); <stl_construct.h> // ++new_finish; // uninitialized_copy(position, finish, new_finish); <stl_uninitialized.h> // destroy(begin(), end()); <stl_construct.h> // deallocate(); //////////////////////////////////////////////////////////////////////////////// iterator insert(iterator position, const T& x) { size_type n = position - begin(); if (finish != end_of_storage && position == end()) { construct(finish, x); ++finish; } else insert_aux(position, x); return begin() + n; } iterator insert(iterator position) { return insert(position, T()); } void pop_back() { --finish; destroy(finish); } iterator erase(iterator position) { if (position + 1 != end()) copy(position + 1, finish, position); --finish; destroy(finish); return position; } iterator erase(iterator first, iterator last) { iterator i = copy(last, finish, first); // 析构掉需要析构的元素 destroy(i, finish); finish = finish - (last - first); return first; } // 调整size, 但是并不会重新分配内存空间 void resize(size_type new_size, const T& x) { if (new_size < size()) erase(begin() + new_size, end()); else insert(end(), new_size - size(), x); } void resize(size_type new_size) { resize(new_size, T()); } void clear() { erase(begin(), end()); } protected: // 分配空间, 并且复制对象到分配的空间处 iterator allocate_and_fill(size_type n, const T& x) { iterator result = data_allocator::allocate(n); uninitialized_fill_n(result, n, x); return result; } // 提供插入操作 //////////////////////////////////////////////////////////////////////////////// // insert_aux(iterator position, const T& x) // | // |---------------- 容量是否足够? // ↓ // ----------------------------------------- // Yes | | No // | | // ↓ | // 从opsition开始, 整体向后移动一个位置 | // construct(finish, *(finish - 1)); | // ++finish; | // T x_copy = x; | // copy_backward(position, finish - 2, finish - 1); | // *position = x_copy; | // ↓ // data_allocator::allocate(len); // uninitialized_copy(start, position, new_start); // construct(new_finish, x); // ++new_finish; // uninitialized_copy(position, finish, new_finish); // destroy(begin(), end()); // deallocate(); //////////////////////////////////////////////////////////////////////////////// template <class T, class Alloc> void 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 // 已无备用空间 { const size_type old_size = size(); const size_type len = old_size != 0 ? 2 * old_size : 1; // 以上配置元素:如果大小为0,则配置1(个元素大小) // 如果大小不为0,则配置原来大小的两倍 // 前半段用来放置原数据,后半段准备用来放置新数据 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; } } //////////////////////////////////////////////////////////////////////////////// // 在指定位置插入n个元素 //////////////////////////////////////////////////////////////////////////////// // insert(iterator position, size_type n, const T& x) // | // |---------------- 插入元素个数是否为0? // ↓ // ----------------------------------------- // No | | Yes // | | // | ↓ // | return; // |----------- 内存是否足够? // | // ------------------------------------------------- // Yes | | No // | | // |------ (finish - position) > n? | // | 分别调整指针 | // ↓ | // ---------------------------- | // No | | Yes | // | | | // ↓ ↓ | // 插入操作, 调整指针 插入操作, 调整指针 | // ↓ // data_allocator::allocate(len); // new_finish = uninitialized_copy(start, position, new_start); // new_finish = uninitialized_fill_n(new_finish, n, x); // new_finish = uninitialized_copy(position, finish, new_finish); // destroy(start, finish); // deallocate(); //////////////////////////////////////////////////////////////////////////////// template <class T, class Alloc> void insert(iterator position, size_type n, const T& x) { // 如果n为0则不进行任何操作 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; // 将vector 尾端标记后移 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); // 以下再将新增元素(初值皆为n)填入新空间 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 /* __STL_USE_EXCEPTIONS */ destroy(start, finish); deallocate(); start = new_start; finish = new_finish; end_of_storage = new_start + len; } } } };
List:
//////////////////////////////////////////////////////////////////////////////// // list结点, 提供双向访问能力 //////////////////////////////////////////////////////////////////////////////// // -------- -------- -------- -------- // | next |---------->| next |---------->| next |---------->| next | // -------- -------- -------- -------- // | prev |<----------| prev |<----------| prev |<----------| prev | // -------- -------- -------- -------- // | data | | data | | data | | data | // -------- -------- -------- -------- //////////////////////////////////////////////////////////////////////////////// template <class T> struct __list_node { typedef void* void_pointer; void_pointer next; void_pointer prev; T data; }; // 至于为什么不使用默认参数, 这个是因为有一些编译器不能提供推导能力, // 而作者又不想维护两份代码, 故不使用默认参数 template<class T, class Ref, class Ptr> struct __list_iterator { typedef __list_iterator<T, T&, T*> iterator; // STL标准强制要求 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的节点 __list_iterator(link_type x) : node(x) {} __list_iterator() {} __list_iterator(const iterator& x) : node(x.node) {} // 在STL算法中需要迭代器提供支持 bool operator==(const self& x) const { return node == x.node; } bool operator!=(const self& x) const { return node != x.node; } // 以下对迭代器取值(dereference),取的是节点的数据值 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; } // 前缀自减 self& operator--() { node = (link_type)((*node).prev); return *this; } self operator--(int) { self tmp = *this; --*this; return tmp; } }; //////////////////////////////////////////////////////////////////////////////// // list不仅是个双向链表, 而且还是一个环状双向链表 //////////////////////////////////////////////////////////////////////////////// // end() 头结点 begin() // ↓ ↓ ↓ // -------- -------- -------- -------- // ---->| next |---------->| next |---------->| next |---------->| next |------ // | -------- -------- -------- -------- | // | --| prev |<----------| prev |<----------| prev |<----------| prev |<--| | // | | -------- -------- -------- -------- | | // | | | data | | data | | data | | data | | | // | | -------- -------- -------- -------- | | // | | | | // | | -------- -------- -------- -------- | | // ---|-| next |<----------| next |<----------| next |<----------| next |<--|-- // | -------- -------- -------- -------- | // ->| prev |---------->| prev |---------->| prev |---------->| prev |---- // -------- -------- -------- -------- // | data | | data | | data | | data | // -------- -------- -------- -------- //////////////////////////////////////////////////////////////////////////////// // 默认allocator为alloc, 其具体使用版本请参照<stl_alloc.h> template <class T, class Alloc = alloc> class list { protected: typedef void* void_pointer; typedef __list_node<T> list_node; // 专属之空间配置器,每次配置一个节点大小 typedef simple_alloc<list_node, Alloc> list_node_allocator; public: typedef T value_type; typedef value_type* pointer; typedef value_type& reference; typedef list_node* link_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef __list_iterator<T, T&, T*> iterator; protected: link_type node ; // 只要一个指针,便可表示整个环状双向链表 // 分配一个新结点, 注意这里并不进行构造, // 构造交给全局的construct, 见<stl_stl_uninitialized.h> link_type get_node() { return list_node_allocator::allocate(); } // 释放指定结点, 不进行析构, 析构交给全局的destroy void put_node(link_type p) { list_node_allocator::deallocate(p); } // 产生(配置并构造)一个节点, 首先分配内存, 然后进行构造 // 注: commit or rollback 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); } protected: // 用于空链表的建立 void empty_initialize() { node = get_node(); // 配置一个节点空间,令node指向它 node->next = node; // 令node头尾都指向自己,不设元素值 node->prev = node; } // 创建值为value共n个结点的链表 // 注: commit or rollback void fill_initialize(size_type n, const T& value) { empty_initialize(); __STL_TRY { // 此处插入操作时间复杂度O(1) insert(begin(), n, value); } __STL_UNWIND(clear(); put_node(node)); } public: list() { empty_initialize(); } iterator begin() { return (link_type)((*node).next); } // 链表成环, 当指所以头节点也就是end iterator end() { return node; } // 头结点指向自身说明链表中无元素 bool empty() const { return node->next == node; } // 使用全局函数distance()进行计算, 时间复杂度O(n) size_type size() const { size_type result = 0; distance(begin(), end(), result); return result; } size_type max_size() const { return size_type(-1); } reference front() { return *begin(); } reference back() { return *(--end()); } //////////////////////////////////////////////////////////////////////////////// // 在指定位置插入元素 //////////////////////////////////////////////////////////////////////////////// // insert(iterator position, const T& x) // ↓ // create_node(x) // p = get_node();-------->list_node_allocator::allocate(); // construct(&p->data, x); // ↓ // tmp->next = position.node; // tmp->prev = position.node->prev; // (link_type(position.node->prev))->next = tmp; // position.node->prev = tmp; //////////////////////////////////////////////////////////////////////////////// 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; } // 指定位置插入n个值为x的元素, 详细解析见实现部分 void insert(iterator pos, size_type n, const T& x); void insert(iterator pos, int n, const T& x) { insert(pos, (size_type)n, x); } void insert(iterator pos, long n, const T& x) { insert(pos, (size_type)n, x); } // 在链表前端插入结点 void push_front(const T& x) { insert(begin(), x); } // 在链表最后插入结点 void push_back(const T& x) { insert(end(), x); } // 移除迭代器position所指节点 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); } // 擦除一个区间的结点, 详细解析见实现部分 iterator erase(iterator first, iterator last); void resize(size_type new_size, const T& x); void resize(size_type new_size) { resize(new_size, T()); } void clear(); // 删除链表第一个结点 void pop_front() { erase(begin()); } // 删除链表最后一个结点 void pop_back() { iterator tmp = end(); erase(--tmp); } list(size_type n, const T& value) { fill_initialize(n, value); } list(int n, const T& value) { fill_initialize(n, value); } list(long n, const T& value) { fill_initialize(n, value); } ~list() { // 释放所有结点 // 使用全局函数distance()进行计算, 时间复杂度O(n) size_type size() const { size_type result = 0; distance(begin(), end(), result); return result; } clear(); // 释放头结点 put_node(node); } list<T, Alloc>& operator=(const list<T, Alloc>& x); protected: //////////////////////////////////////////////////////////////////////////////// // 将[first, last)内的所有元素移动到position之前 // 如果last == position, 则相当于链表不变化, 不进行操作 //////////////////////////////////////////////////////////////////////////////// // 初始状态 // first last // ↓ ↓ // -------- -------- -------- -------- -------- -------- // | next |-->| next |-->| next | | next |-->| next |-->| next | // ... -------- -------- -------- ... -------- -------- -------- ... // | prev |<--| prev |<--| prev | | prev |<--| prev |<--| prev | // -------- -------- -------- -------- -------- -------- // // position // ↓ // -------- -------- -------- -------- -------- -------- // | next |-->| next |-->| next |-->| next |-->| next |-->| next | // ... -------- -------- -------- -------- -------- -------- ... // | prev |<--| prev |<--| prev |<--| prev |<--| prev |<--| prev | // -------- -------- -------- -------- -------- -------- // // 操作完成后状态 // first // | // --------------|-------------------------------------- // | ------------|------------------------------------ | last // | | ↓ | | ↓ // -------- | | -------- -------- -------- | | -------- -------- // | next |-- | ----->| next |-->| next | | next |----- | -->| next |-->| next | // ... -------- | | -------- -------- ... -------- | | -------- -------- ... // | prev |<--- | ---| prev |<--| prev | | prev |<-- | -----| prev |<--| prev | // -------- | | -------- -------- -------- | | -------- -------- // | | | | // | ------ | | // ------- | ------------------------------ | // | | | | // | | | ----------------------------- // | | | | // | | | | position // | | | | ↓ // -------- -------- | | | | -------- -------- -------- -------- // | next |-->| next |-- | | -->| next |-->| next |-->| next |-->| next | // ... -------- -------- | | -------- -------- -------- -------- ... // | prev |<--| prev |<--- ------| prev |<--| prev |<--| prev |<--| prev | // -------- -------- -------- -------- -------- -------- //////////////////////////////////////////////////////////////////////////////// void transfer(iterator position, iterator first, iterator last) { if (position != last) // 如果last == position, 则相当于链表不变化, 不进行操作 { (*(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; } } public: // 将链表x移动到position所指位置之前 void splice(iterator position, list& x) { if (!x.empty()) transfer(position, x.begin(), x.end()); } // 将链表中i指向的内容移动到position之前 void splice(iterator position, list&, iterator i) { iterator j = i; ++j; if (position == i || position == j) return; transfer(position, i, j); } // 将[first, last}元素移动到position之前 void splice(iterator position, list&, iterator first, iterator last) { if (first != last) transfer(position, first, last); } void remove(const T& value); void unique(); void merge(list& x); void reverse(); void sort(); }; // 销毁所有结点, 将链表置空 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原始状态 node->next = node; node->prev = node; } // 链表赋值操作 // 如果当前容器元素少于x容器, 则析构多余元素, // 否则将调用insert插入x中剩余的元素 template <class T, class Alloc> list<T, Alloc>& list<T, Alloc>::operator=(const list<T, Alloc>& x) { if (this != &x) { iterator first1 = begin(); iterator last1 = end(); const_iterator first2 = x.begin(); const_iterator last2 = x.end(); while (first1 != last1 && first2 != last2) *first1++ = *first2++; if (first2 == last2) erase(first1, last1); else insert(last1, first2, last2); } return *this; } // 移除容器内所有的相邻的重复结点 // 时间复杂度O(n) // 用户自定义数据类型需要提供operator ==()重载 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; } } // 假设当前容器和x都已序, 保证两容器合并后仍然有序 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(); // 注意:前提是,两个lists都已经递增排序 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); }
Deque:
一、deque的中控器 deque是连续空间(至少逻辑上看来如此),连续线性空间总令我们联想到array或vector。 array无法成长,vector虽可成长,却只能向尾端成长,而且其所谓的成长原是个假象,事实 上是(1)另觅更大空间;(2)将原数据复制过去;(3)释放原空间三部曲。如果不是vector 每次配置新空间时都有留下一些余裕,其成长假象所带来的代价将是相当高昂。 deque系由一段一段的定量连续空间构成。一旦有必要在deque的前端或尾端增加新空间,便 配置一段定量连续空间,串接在整个deque的头端或尾端。deque的最大任务,便是在这些分 段的定量连续空间上,维护其整体连续的假象,并提供随机存取的借口。避开了“重新配置、 复制、释放”的轮回,代价则是复杂的迭代器架构。 受到分段连续线性空间的字面影响,我们可能以为deque的实现复杂度和vector相比虽不中 亦不远矣,其实不然。主要因为,既是分段连续线性空间,就必须有中央控制,而为了维持 整体连续的假象,数据结构的设计及迭代器前进后退等操作都颇为繁琐。deque的实现代码 分量远比vector或list都多得多。 deque采用一块所谓的map(注意,不是STL的map容器)作为主控。这里所谓map是一小块 连续空间,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的) 连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL 允许我们指定 缓冲区大小,默认值0表示将使用512 bytes 缓冲区。 二、deque的迭代器 让我们思考一下,deque的迭代器应该具备什么结构,首先,它必须能够指出分段连续空 间(亦即缓冲区)在哪里,其次它必须能够判断自己是否已经处于其所在缓冲区的边缘, 如果是,一旦前进或后退就必须跳跃至下一个或上一个缓冲区。为了能够正确跳跃,dequ e必须随时掌握管控中心(map)。所以在迭代器中需要定义:当前元素的指针,当前元素 所在缓冲区的起始指针,当前元素所在缓冲区的尾指针,指向map中指向所在缓区地址的指针。 在进行迭代器的移动时,需要考虑跨缓冲区的情况。 重载前加(减),在实现后加(减)时,调用重载的前加(减)。 重载+=,实现+时,直接调用+=,实现-=时,调用+=负数,实现-时,调用-=. //当需要实现新的功能时,最好使用已经重载好的操作,即方便有安全。。。。 另外,deque在效率上来说是不够vector好的,因此有时候在对deque进行sort的时候,需要先 将元素移到vector再进行sort,然后移回来。 构造函数:根据缓冲区设置大小和元素个数,决定map的大小;给map分配空间,根据缓冲区的个 数,分配缓冲区,默认指定一个缓冲区; 设置start和finish迭代器,满足左闭右开的原则。 push_back:如果空间满足,直接插入;不满足,调用push_back_aux。 push_back_aux:先调用reverse_map_at_back,若符合某种条件,重换一个map;分配空间。 reserve_map_at_back:看看map有没有满,满的话,调用reallocate_map。 reallocate_map:如果前端或后端pop过多,就会导致大量的空闲空间,如果是这种情况,则不用 新分配空间,调整一下start的位置即可; 如果不够,则需要重新申请空间。 pop:析构元素,如果是最后一块还需要删除空间。 erase:需要判断,前面的元素少还是后面的元素少,移动较少的部分。 insert:判断位置,如果为前端或后端直接调用push操作,否则,移动较少的一端。 deque的构造与内存管理: 由于deque的设计思想就是由一块块的缓存区连接起来的,因此它的内存管理会比较复杂。插入的 时候要考虑是否要跳转缓存区、是否要新建map节点(和vector一样,其实是重新分配一块空间给 map,删除原来空间)、插入后元素是前面元素向前移动还是后面元素向后面移动(谁小移动谁) 。而在删除元素的时候,考虑是将前面元素后移覆盖需要移除元素的地方还是后面元素前移覆盖 (谁小移动谁)。移动完以后要析构冗余的元素,释放冗余的缓存区。 // deque的特性: // 对于任何一个迭代器i // i.node是map array中的某元素的地址. i.node的内容是一个指向某个结点的头的指针 // i.first == *(i.node) // i.last == i.first + node_size // i.cur是一个指向[i.first, i.last)之间的指针 // 注意: 这意味着i.cur永远是一个可以解引用的指针, // 即使其是一个指向结尾后元素的迭代器 // // 起点和终点总是非奇异(nonsingular)的迭代器. // 注意: 这意味着空deque一定有一个node, 而一个具有N个元素的deque // (N是Buffer Size)一定有有两个nodes // // 对于除了start.node和finish.node之外的每一个node, 每一个node中的元素 // 都是一个初始化过的对象. 如果start.node == finish.node, // 那么[start.cur, finish.cur)都是未初始化的空间. // 否则, [start.cur, start.last)和[finish.first, finish.cur)都是初始化的对象, // 而[start.first, start.cur)和[finish.cur, finish.last)是未初始化的空间 // // [map, map + map_size)是一个合法的非空区间 // [start.node, finish.node]是内含在[map, map + map_size)区间的合法区间 // 一个在[map, map + map_size)区间内的指针指向一个分配过的node, // 当且仅当此指针在[start.node, finish.node]区间内 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)); } // __deque_iterator的数据结构 template <class T, class Ref, class Ptr, size_t BufSiz> struct __deque_iterator { typedef __deque_iterator<T, T&, T*> iterator; typedef __deque_iterator<T, const T&, const T*> const_iterator; static size_t buffer_size() {return __deque_buf_size(0, 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; // 指向管控中心 //////////////////////////////////////////////////////////////////////////////// // 这个是deque内存管理的关键, 其模型如下 //////////////////////////////////////////////////////////////////////////////// // // --------------------------------------------- // map-->| | | | | | | ..... | | | |<------------------ // --------------------------------------------- | // | | // | | // | node | // | 缓冲区buffer, 这里实际存储元素 | // | --------------------------------------------- | // --->| | | | | | | ..... | | | X | | // --------------------------------------------- | // ↑ ↑ ↑ | // ------ | | | // | | | | // | ----------- --------------------------- | // ----|----- | | // | | | | // | | | | // | | | | // --------------------------- | // | cur | first | end | map |------------------------------ // --------------------------- // 迭代器, 其内部维护着一个缓冲区状态 //////////////////////////////////////////////////////////////////////////////// __deque_iterator(T* x, map_pointer y) : cur(x), first(*y), last(*y + buffer_size()), node(y) {} __deque_iterator() : cur(0), first(0), last(0), node(0) {} __deque_iterator(const iterator& x) : cur(x.cur), first(x.first), last(x.last), node(x.node) {} reference operator*() const { return *cur; } // 判断两个迭代器间的距离 difference_type operator-(const self& x) const { return difference_type(buffer_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur); } //////////////////////////////////////////////////////////////////////////////// // 下面重载的这些运算符是让deque从外界看上去维护的是一段连续空间的关键!!! // 前缀自增 //////////////////////////////////////////////////////////////////////////////// // 如果当前迭代器指向元素是当前缓冲区的最后一个元素, // 则将迭代器状态调整为下一个缓冲区的第一个元素 //////////////////////////////////////////////////////////////////////////////// // 不是当前缓冲区最后一个元素 // // 执行前缀自增前的状态 // first cur end // ↓ ↓ ↓ // --------------------------------------------- // | | | | | | | ..... | | | X | <----- 当前缓冲区 // --------------------------------------------- // // 执行完成后的状态 // first cur end // ↓ ↓ ↓ // --------------------------------------------- // | | | | | | | ..... | | | X | <----- 当前缓冲区 // --------------------------------------------- // //////////////////////////////////////////////////////////////////////////////// // 当前元素为当前缓冲区的最后一个元素 // // 执行前缀自增前的状态 // first cur end // ↓ ↓ ↓ // --------------------------------------------- // | | | | | | | ..... | | | X | <----- 当前缓冲区 // --------------------------------------------- // // 执行完成后的状态 // first end // ↓ ↓ // --------------------------------------------- // | | | | | | | ..... | | | 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个元素, n可以为负 //////////////////////////////////////////////////////////////////////////////// // operator+=(difference_type n) // ↓ // offset = n + (cur - first) // | // |---------- offset > 0 ? && // | 移动后是否超出当前缓冲区? // ---------------------------- // No | | Yes // | | // ↓ |---------- offset > 0? // cur += n; | // ---------------------------- // Yes | | No // | | // ↓ | // 计算要向后移动多少个缓冲区 | // node_offset = | // offset / difference_type | // (buffer_size()); ↓ // | 计算要向前移动多少个缓冲区 // | node_offset = -difference_type // | ((-offset - 1) / buffer_size()) - 1; // | | // ---------------------------- // | // | // ↓ // 调整缓冲区 // set_node(node + node_offset); // 计算并调整cur指针 //////////////////////////////////////////////////////////////////////////////// // 以下实现随机存取。迭代器可以直接跳跃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 + node_offset); // 切换至正确的元素 cur = first + (offset - node_offset * difference_type(buffer_size())); } return *this; } self operator+(difference_type n) const { self tmp = *this; // 这里调用了operator +=()可以自动调整指针状态 return tmp += n; } // 将n变为-n就可以使用operator +=()了, 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); } void set_node(map_pointer new_node) { node = new_node; first = *new_node; last = first + difference_type(buffer_size()); } }; // deque的数据结构 template <class T, class Alloc = alloc, size_t BufSiz = 0> class deque { public: // Basic types typedef T value_type; typedef value_type* pointer; typedef value_type& reference; typedef size_t size_type; typedef ptrdiff_t difference_type; public: // Iterators typedef __deque_iterator<T, T&, T*, BufSiz> iterator; protected: // Internal typedefs typedef pointer* map_pointer; // 这个提供STL标准的allocator接口, 见<stl_alloc.h> typedef simple_alloc<value_type, Alloc> data_allocator; typedef simple_alloc<pointer, Alloc> map_allocator; // 获取缓冲区最大存储元素数量 static size_type buffer_size() { return __deque_buf_size(BufSiz, sizeof(value_type)); } static size_type initial_map_size() { return 8; } protected: // Data members iterator start; // 起始缓冲区 iterator finish; // 最后一个缓冲区 // 指向map, map是一个连续的空间, 其每个元素都是一个指针,指向一个节点(缓冲区) map_pointer map; size_type map_size; // map容量 public: iterator begin() { return start; } iterator end() { return finish; } // 提供随机访问能力, 其调用的是迭代器重载的operator [] // 其实际地址需要进行一些列的计算, 效率有损失 reference operator[](size_type n) { return start[difference_type(n)]; } reference front() { return *start; } reference back() { iterator tmp = finish; --tmp; return *tmp; } // 当前容器拥有的元素个数, 调用迭代器重载的operator - size_type size() const { return finish - start;; } size_type max_size() const { return size_type(-1); } // deque为空的时, 只有一个缓冲区 bool empty() const { return finish == start; } public: // Constructor, destructor. deque() : start(), finish(), map(0), map_size(0) { create_map_and_nodes(0); } deque(size_type n, const value_type& value) : start(), finish(), map(0), map_size(0) { fill_initialize(n, value); } deque(int n, const value_type& value) : start(), finish(), map(0), map_size(0) { fill_initialize(n, value); } ~deque() { destroy(start, finish); // <stl_construct.h> destroy_map_and_nodes(); } deque& operator= (const deque& x) { // 其实我觉得把这个操作放在if内效率更高 const size_type len = size(); if (&x != this) { // 当前容器比x容器拥有元素多, 析构多余元素 if (len >= x.size()) erase(copy(x.begin(), x.end(), start), finish); // 将x所有超出部分的元素使用insert()追加进去 else { const_iterator mid = x.begin() + difference_type(len); copy(x.begin(), mid, start); insert(finish, mid, x.end()); } } return *this; } 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); } void pop_back() { if (finish.cur != finish.first) // 最后缓冲区有一个(或更多)元素 { --finish.cur; // 调整指针,相当于排除了最后元素 destroy(finish.cur); // 将最后元素析构 } else // 最后缓冲区没有任何元素 pop_back_aux(); // 这里将进行缓冲区的释放工作 } void pop_front() { if (start.cur != start.last - 1) // 第一缓冲区有两个(或更多)元素 { destroy(start.cur); // 将第一元素析构 ++start.cur; //调整指针,相当于排除了第一元素 } else // 第一缓冲区仅有一个元素 pop_front_aux(); // 这里将进行缓冲区的释放工作 } public: // Insert //////////////////////////////////////////////////////////////////////////////// // 在指定位置前插入元素 //////////////////////////////////////////////////////////////////////////////// // insert(iterator position, const value_type& x) // | // |---------------- 判断插入位置 // | // ----------------------------------------------- // deque.begin() | deque.emd() | | // | | | // ↓ ↓ | // push_front(x); push_back(x); | // ↓ // insert_aux(position, x); // 具体剖析见后面实现 //////////////////////////////////////////////////////////////////////////////// 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); } } iterator insert(iterator position) { return insert(position, value_type()); } // 详解见实现部分 void insert(iterator pos, size_type n, const value_type& x); void insert(iterator pos, int n, const value_type& x) { insert(pos, (size_type) n, x); } void insert(iterator pos, long n, const value_type& x) { insert(pos, (size_type) n, x); } void resize(size_type new_size) { resize(new_size, value_type()); } public: // 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; } iterator erase(iterator first, iterator last); void clear(); protected: // 详解见实现部分 void push_back_aux(const value_type& t); void push_front_aux(const value_type& t); void pop_back_aux(); void pop_front_aux(); iterator insert_aux(iterator pos, const value_type& x); void insert_aux(iterator pos, size_type n, const value_type& x); // 分配内存, 不进行构造 pointer allocate_node() { return data_allocator::allocate(buffer_size()); } // 释放内存, 不进行析构 void deallocate_node(pointer n) { data_allocator::deallocate(n, buffer_size()); } }; //////////////////////////////////////////////////////////////////////////////// // 清除[first, last)区间的所有元素 //////////////////////////////////////////////////////////////////////////////// // erase(iterator first, iterator last) // | // |---------------- 是否要删除整个区间? // | // ------------------------------------------ // Yes | | No // | | // ↓ | --- 判断哪侧元素少 // clear(); ↓ // ----------------------------------------------------------------- // 左侧少 | 右侧少 | // | | // ↓ ↓ // copy_backward(start, first, last); copy(last, finish, first); // new_start = start + n; new_finish = finish - n; // 析构多余的元素 析构多余的元素 // destroy(start, new_start); destroy(new_finish, finish); // 释放多余内存空间 释放多余内存空间 // for (...) for (...) // ... ... // 更新map状态 更新map状态 //////////////////////////////////////////////////////////////////////////////// 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; } } 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; // 调整状态 } // 只有当finish.cur == finish.last - 1 时才会被调用 // 也就是说,只有当最后一个缓冲区只剩下一个备用元素空间时才会被调用 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,令其指向新节点 finish.cur = finish.first; // 设定finish的状态 } __STL_UNWIND(deallocate_node(*(finish.node + 1))); } // Called only if start.cur == start.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(); __STL_TRY { start.set_node(start.node - 1); // 改变start,令其指向新节点 start.cur = start.last - 1; // 设定start的状态 construct(start.cur, t_copy); // 针对标的元素设值 } catch(...) { start.set_node(start.node + 1); start.cur = start.first; deallocate_node(*(start.node - 1)); throw; } } // 只有当 finish.cur == finish.first 时才会被调用 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状态,使指向 finish.cur = finish.last - 1; // 上一个缓冲区的最后一个元素 destroy(finish.cur); // 将该元素析构 } // 只有当 start.cur == start.last - 1 时才会被调用 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状态,使指向 start.cur = start.first; // 下一个缓冲区的第一个元素 } //////////////////////////////////////////////////////////////////////////////// // 在指定位置前插入元素 //////////////////////////////////////////////////////////////////////////////// // insert_aux(iterator pos, const value_type& x) // | // |----------- 判断pos前端元素少还是后端元素少 // | // ----------------------------------------------- // 前端少 | 后端少 | // | | // ↓ | // 进行相关操作 进行相关操作 //////////////////////////////////////////////////////////////////////////////// // 下面以pos前面元素少的情形进行说明, 为了简化, 假设操作不会超过一个缓冲区区间 // // 插入前状态 // start pos end // ↓ ↓ ↓ // --------------------------------------------------------------------- // | | | | | | | | | | | | | | | | | X | // --------------------------------------------------------------------- // // 需要进行操作的区间 // 需要拷贝的区间 // ------------- // start | | end // ↓ ↓ ↓ ↓ // --------------------------------------------------------------------- // | | | | | | | | | | | | | | | | | X | // --------------------------------------------------------------------- // ↑ ↑ ↑ ↑ // front1 | | | // | | | // front2 | | // | | // pos | // | // pos1 // 拷贝操作完成后 // // 这是[front2, pos1) // ------------- --------- 这里是给待插入元素预留的空间 // start | | | end // ↓ ↓ ↓ ↓ ↓ // --------------------------------------------------------------------- // | | | | | | | | | | | | | | | | | X | // --------------------------------------------------------------------- // ↑ // 这里存储的是原来的front() // //////////////////////////////////////////////////////////////////////////////// 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; }