4 序列式容器

来源:互联网 发布:ubuntu查看selinux 编辑:程序博客网 时间:2024/04/28 16:45

4.2 vector

template <class T, class Alloc = alloc>class vector{typedef T value_type; typedef value_type* iterator;protected:iterator start; // 表示目前使用空間的頭iterator finish; // 表示目前使用空間的尾iterator end_of_storage;// 表示目前可用空間的尾...};


成员函数举例:注意其中的内存管理

void vector<T, Alloc>::insert(iterator position, size_type n, const T& x){if (n != 0) { // 當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_EXCEPTIONScatch(...) {// 如有異常發生,實現"commit or rollback" semantics.destroy(new_start, new_finish);data_allocator::deallocate(new_start, len);throw;}# endif /* __STL_USE_EXCEPTIONS */// 以㆘清除並釋放舊的vectordestroy(start, finish);   //全局函数deallocate();// 以㆘調整水位標記start = new_start;finish = new_finish;end_of_storage = new_start + len;}}}


4.3 list

1、list的节点(node)

template <class T>struct __list_node{typedef void* void_pointer;void_pointer prev;// 型別為void*。其实可設為__list_node<T>*void_pointer next;T data;};


2、list的迭代器

template<class T, class Ref, class Ptr>struct __list_iterator{typedef __list_iterator<T, T&, T*>  iterator;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的節點// constructor__list_iterator(link_type x) : node(x) {}__list_iterator() {}__list_iterator(const iterator& x) : node(x.node) {}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; }// 以㆘是迭代器的成員存取(member access)運算子的標準作法。pointer operator->() const { return &(operator*()); }// 對迭代器累加1,就是前進㆒個節點self& operator++() {node = (link_type)((*node).next);return *this;}self operator++(int) {self tmp = *this;++*this;return tmp;}// 對迭代器遞減1,就是後退㆒個節點self& operator--() {node = (link_type)((*node).prev);return *this;}self operator--(int) {self tmp = *this;--*this;return tmp;}};


 

3、list——实现为一个环状双向列表

template <class T, class Alloc = alloc> // 預設使用alloc 為配置器class list{protected:typedef __list_node<T> list_node;public:typedef list_node* link_type;protected:link_type node; // 只要㆒個指標,便可表示整个环状双向链表,node指向置于尾端的空节点...public:iterator begin() { return (link_type)((*node).next); }iterator end() { return node; }};

4、元素操作
insert, push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort

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); // 移除之elsefirst = next; // 調整指针next = first; // 修正區段范围}}


list不能使用STL算法的sort(),必须使用自己的成员函数sort,因为STL算法sort()只接受RandomAccessIterator。

// 將[first,last) 內的所有元素搬移到position 之前。它是spice(), reserve(), merge()的基础。void transfer(iterator position, iterator first, iterator last)// “本函式採用quick sort”。这是书中原话,我觉得更像是归并排序的迭代形式。template <class T, class Alloc>void list<T, Alloc>::sort() {// 以㆘判斷,如果是空白串列,或僅有㆒個元素,就不做任何動作。// 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。if (node->next == node || link_type(node->next)->next == node)return;// ㆒些新的lists,做為㆗介資料存放區list<T, Alloc> carry;list<T, Alloc> counter[64];int fill = 0;while (!empty()) {carry.splice(carry.begin(), *this, begin());int i = 0;while(i < fill && !counter[i].empty()) {counter[i].merge(carry);carry.swap(counter[i++]);}carry.swap(counter[i]);if (i == fill) ++fill;}for (int i = 1; i < fill; ++i)counter[i].merge(counter[i-1]);swap(counter[fill-1]);}

4.4 deque

虽然deque也提供random access iterator,但是并不是普通指针,所以尽可能使用vector。对deque进行的排序操作,为了最高效率,可将deque先完整复制到一个vector上,将vector排序后(利用STL sort算法),再复制会deque。

 

1、deque的中控器

deque采用一块所谓的map(不是STL的map容器),为一小块连续空间,其中每个元素都是指针,指向较大的连续线性空间(缓冲器),缓冲区才是deque的存储空间主体。

 

2、deque的迭代器

template <class T, class Ref, class Ptr,size_t BufSiz>struct __deque_iterator{ // 未繼承std::iteratortypedef __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)); }// 未繼承std::iterator,所以必須自行撰寫五個必要的迭代器相應型別(第3章)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; // 此迭代器所指之緩衝區㆗的現行(current)元素T* first; // 此迭代器所指之緩衝區的頭T* last; // 此迭代器所指之緩衝區的尾(含備用空間)map_pointer node; // 指向管控㆗心...};

// 以下實現隨機存取。迭代器可以直接跳躍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;}// 參考 More Effective C++, item22: Consider using op= instead of// stand-alone op.    A = B + n;self operator+(difference_type n) const {self tmp = *this;return tmp +=n; // 喚起operator+=}

 

3、deque的数据结构

template <class T, class Alloc = alloc, size_t BufSiz = 0>class deque{public:  // Basic typestypedef T value_type;typedef value_type* pointer;typedef size_t size_type;typedef __deque_iterator<T, T&, T*, BufSiz> iterator;protected:  // Internal typedefs// 元素的指標的指標(pointer of pointer of T)typedef pointer* map_pointer;protected:  // Data membersiterator start; // 表現第㆒個節點。iterator finish; // 表現最後㆒個節點map_pointer map; // 指向map,map是塊連續空間,其內的每個元素// 都是㆒個指標(稱為節點),指向㆒塊緩衝區。size_type map_size; // map內可容納多少指標。...}; reference back() {iterator tmp = finish;--tmp; // 喚起__deque_iterator<>::operator--return *tmp;// 喚起__deque_iterator<>::operator*// 以㆖㆔行何不改為:return *(finish-1);// 因為__deque_iterator<> 沒有為(finish-1) 定義運算子?!}