1. 序:
本文参考了侯捷的 《STL 源码分析》一书,出于兴趣,自行实现了简单的 list 容器。
学习了 STL 的 list 容器的源代码,确实能够提高写链表代码的能力。其中的 sort 函数,可谓是非常神奇。。。
2. 实现的细节
STL 的 list 容器采用了一个带有尾节点的环状双向链表。 如下图所示:
// Last Update:2014-04-20 18:39:47 /** * @file my_list.h * @brief a simple list * @author [email protected] * @version 0.1.00 * @date 2014-04-18 */ #ifndef MY_LIST_H #define MY_LIST_H #include <iostream> #include <cstddef> #include <cassert> /** * list node */ template<class T> struct list_node { typedef list_node<T>* pointer; pointer prev; pointer next; T data; }; /** * list's iterator * users can use it to iteratate over this list container */ template<class T> struct list_iterator { typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef list_iterator iterator; list_iterator(list_node<T> *p = NULL) : node(p) {} reference operator*() { return node->data; } iterator& operator++(){ node = node->next; return *this; } iterator operator++(int){ iterator tmp = *this; ++*this; return tmp; } iterator& operator--(){ node = node->prev; return *this; } iterator operator--(int){ iterator tmp = *this; --*this; return tmp; } bool operator==(const iterator &rhs){ return node == rhs.node; } bool operator!=(const iterator &rhs){ return node != rhs.node; } list_node<T> *node; }; /** * a simple list container */ template<class T> class MyList { public: typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef list_iterator<T> iterator; typedef const list_iterator<T> const_iterator; typedef T& reference; typedef const T& const_reference; typedef list_node<T>* link_type; MyList(); MyList(size_type n, T value = T()); //template<class InputIterator> //MyList(InputIterator first, InputIterator last); // copy control MyList(const MyList&); MyList& operator=(const MyList&); ~MyList(); bool empty() const { return node->next == node;} difference_type size() const; iterator begin() {return iterator(node->next);} iterator end() {return iterator(node);} iterator begin() const {return iterator(node->next);} iterator end() const {return iterator(node);} iterator rbegin() {return iterator(node->prev);} iterator rbegin() const {return iterator(node->prev);} iterator insert(iterator position, const T& x); void swap(MyList& ); void push_back(const T& x); void pop_back() { iterator tmp = end(); erase(--tmp); } void push_front(const T& x); void pop_front() {erase(begin());} void reverse(); void merge(MyList &); void sort(); void remove(const T&x); iterator erase(iterator position); void clear(); void splice(iterator position, MyList& x) { if(!x.empty()){ transfer(x.begin(), x.end()); } } void splice(iterator position, MyList&, iterator i){ iterator j = i; ++ j; if (position == i || position == j) return; transfer(position, i, j); } void splice(iterator position, MyList&, iterator first, iterator last) { if(first != last){ transfer(position, first, last); } } void print(); protected: list_node<T> *node; static std::allocator<list_node<T> > alloc; link_type get_node(){ link_type p = alloc.allocate(1); return p; } void put_node(link_type p){ alloc.deallocate(p, 1); } link_type create_node(const T& x){ link_type p = get_node(); new (&p->data) T(x); return p; } void destroy_node(link_type p){ (&p->data)->~T(); put_node(p); } void empty_initialize(){ node = get_node(); node->prev = node; node->next = node; } void transfer(iterator position, iterator first, iterator last); }; template<class T> std::allocator<list_node<T> > MyList<T>::alloc; template<class T> MyList<T>::MyList() { empty_initialize(); } template<class T> MyList<T>::MyList(size_type n, T value) { empty_initialize(); for(size_type i(0); i!=n; ++i) insert(begin(), value); } template<class T> void MyList<T>::clear() { link_type p = node->next; link_type next(NULL); while(p != node){ next = p->next; destroy_node(p); p = next; } node->prev = node; node->next = node; } template<class T> MyList<T>::~MyList() { clear(); destroy_node(node); node = NULL; } //copy control template<class T> MyList<T>::MyList(const MyList &rhs) { empty_initialize(); for(iterator it = rhs.begin(); it != rhs.end(); ++it) insert(end(), *it); } template<class T> MyList<T>& MyList<T>::operator=(const MyList &rhs) { clear(); for(iterator it = rhs.begin(); it != rhs.end(); ++it) insert(end(), *it); return *this; } template<class T> typename MyList<T>::difference_type MyList<T>::size() const { difference_type len(0); link_type p = node->next; for(; p != node; p = p->next, ++len); return len; } template<class T> typename MyList<T>::iterator MyList<T>::insert(iterator position, const T& x) { link_type new_node = create_node(x); new_node->next = position.node; new_node->prev = position.node->prev; position.node->prev->next = new_node; position.node->prev = new_node; return iterator(new_node); } template<class T> inline void MyList<T>::push_back(const T& x) { insert(end(), x); } template<class T> inline void MyList<T>::push_front(const T& x) { insert(begin(), x); } template<class T> typename MyList<T>::iterator MyList<T>::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); } // remove all nodes equal to x template<class T> void MyList<T>::remove(const T& x) { link_type prev_node(node); link_type cur(node->next); link_type next_node(NULL); while(cur != node) { if(cur->data == x){ /* delete node */ next_node = cur->next; prev_node->next = next_node; next_node->prev = prev_node; destroy_node(cur); cur = next_node; } else{ prev_node = cur; cur = cur->next; } } } /** * move [first, last) ahead of position * an auxillary function */ template<class T> void MyList<T>::transfer(iterator position, iterator first, iterator last) { if(position != last) { link_type first_node = first.node; link_type rear_node = last.node->prev; //separate [first, last) from their list first_node->prev->next = last.node; last.node->prev = first_node->prev; //add [first, last) first_node->prev = position.node->prev; rear_node->next = position.node; position.node->prev->next = first_node; position.node->prev = rear_node; } } template<class T> void MyList<T>::swap(MyList &rhs) { if(this->node != rhs.node){ link_type tmp = node; node = rhs.node; rhs.node = tmp; } } template<class T> void MyList<T>::reverse() { /* length == 0 || length == 1*/ if(node->next == node || node->next->next == node) return; iterator first = begin(), old(NULL); ++ first; while(first != end()){ old = first; ++ first; transfer(begin(), old, first); } } template<class T> void MyList<T>::merge(MyList &x) { iterator first1 = this->begin(); iterator last1 = this->end(); iterator first2 = x.begin(); iterator last2 = x.end(); // *this and x are sorted incrementally while(first1 != last1 && first2 != last2) { if(*first2 < *first1) { iterator next = first2; transfer(first1, first2, ++next); first2 = next; } else ++first1; } if(first2 != last2) { transfer(end(), first2, last2); } assert(x.empty()); } template<class T> void MyList<T>::print() { iterator cur = begin(); while(cur != end()) { std::cout << *cur << " "; ++ cur; } std::cout << std::endl; } /** * interesting sort function for list * std::sort is not fit for list * which requires random iterator */ template<class T> void MyList<T>::sort() { /* length == 0 || length == 1*/ if(node->next == node || node->next->next == node) return; MyList<T> carry; MyList<T> counter[64]; int fill = 0; while(!empty()) { /* carry get the first node */ 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]); } #endif /*MY_LIST_H*/