STL学习——Slist篇
简介
STL中List是双向链表,而Slist是单向链表。它们的区别:Slist的迭代器是单向的Forward Iterator,而list的迭代器是双向的Bidirectional Iterator。Slist所耗用的空间更小,操作更快。它们共同的特点是,插入、移除、接合等操作并不会造成原有的迭代器失效。slist插入时,需要从前遍历,找到插入点的位置。为了更快插入,提供了insert_after,erase_after。slist提供push_front()操作,故其元素次序与元素插入顺序相反。
节点与操作
slist节点和迭代器设计上,使用了继承关系,故较复杂。下面是其节点信息。
// 单向链表的节点基本结构 struct _Slist_node_base { _Slist_node_base* _M_next; }; // 单向链表的节点结构 template <class _Tp> struct _Slist_node : public _Slist_node_base { _Tp _M_data; }; // 全局函数:已知某一节点,插入新节点于其后 inline _Slist_node_base* __slist_make_link(_Slist_node_base* __prev_node, _Slist_node_base* __new_node) { __new_node->_M_next = __prev_node->_M_next; // 令new节点的下一节点为prev节点的下一节点 __prev_node->_M_next = __new_node; return __new_node; } // 查找node节点的前一个节点 inline _Slist_node_base* __slist_previous(_Slist_node_base* __head, const _Slist_node_base* __node) { while (__head && __head->_M_next != __node) // 从头遍历,查找node的前一个节点 __head = __head->_M_next; return __head; } // 查找node节点的前一个节点 inline const _Slist_node_base* __slist_previous(const _Slist_node_base* __head, const _Slist_node_base* __node) { while (__head && __head->_M_next != __node) // 从头遍历,查找node的前一个节点 __head = __head->_M_next; return __head; } // 将before_first与before_after之间的节点插入到pos后面 inline void __slist_splice_after(_Slist_node_base* __pos, _Slist_node_base* __before_first, _Slist_node_base* __before_last) { if (__pos != __before_first && __pos != __before_last) { // 记录before_first的next节点 _Slist_node_base* __first = __before_first->_M_next; // 记录pos的next节点 _Slist_node_base* __after = __pos->_M_next; // 先将befor_first与before_last前后挂接在一起 __before_first->_M_next = __before_last->_M_next; // 将before_first的下一个节点挂接在pos的后面 __pos->_M_next = __first; // 将before_last的next与pos_next进行挂接 __before_last->_M_next = __after; } } // 链表的翻转操作 inline _Slist_node_base* __slist_reverse(_Slist_node_base* __node) { _Slist_node_base* __result = __node; __node = __node->_M_next; __result->_M_next = 0; while(__node) { _Slist_node_base* __next = __node->_M_next; // 记住下一个节点 __node->_M_next = __result; // 将当前节点插入到result节点的最前 __result = __node; // 更新result节点 __node = __next; // 更新node节点 } return __result; // 返回逆转的链表 } // 全局函数:单向链表的大小(元素个数) inline size_t __slist_size(_Slist_node_base* __node) { size_t __result = 0; for ( ; __node != 0; __node = __node->_M_next) ++__result; return __result; } // 单向链表的迭代器基本结构 struct _Slist_iterator_base { typedef size_t size_type; typedef ptrdiff_t difference_type; typedef forward_iterator_tag iterator_category; // 注意,单向 _Slist_node_base* _M_node; // 指向节点基本结构 _Slist_iterator_base(_Slist_node_base* __x) : _M_node(__x) {} void _M_incr() { _M_node = _M_node->_M_next; } // 前进一个节点 bool operator==(const _Slist_iterator_base& __x) const { // 判断链表是否相等 return _M_node == __x._M_node; } bool operator!=(const _Slist_iterator_base& __x) const { // 判断链表是否不相等 return _M_node != __x._M_node; } }; // 单向链表的迭代器结构 template <class _Tp, class _Ref, class _Ptr> struct _Slist_iterator : public _Slist_iterator_base { typedef _Slist_iterator<_Tp, _Tp&, _Tp*> iterator; typedef _Slist_iterator<_Tp, const _Tp&, const _Tp*> const_iterator; typedef _Slist_iterator<_Tp, _Ref, _Ptr> _Self; typedef _Tp value_type; typedef _Ptr pointer; typedef _Ref reference; typedef _Slist_node<_Tp> _Node; _Slist_iterator(_Node* __x) : _Slist_iterator_base(__x) {} // 调用slist<T>::end()时会造成__slist_iterator(0),于是调用上述函数 _Slist_iterator() : _Slist_iterator_base(0) {} // 产生一个暂时对象,引发ctor _Slist_iterator(const iterator& __x) : _Slist_iterator_base(__x._M_node) {} reference operator*() const { return ((_Node*) _M_node)->_M_data; } #ifndef __SGI_STL_NO_ARROW_OPERATOR pointer operator->() const { return &(operator*()); } #endif /* __SGI_STL_NO_ARROW_OPERATOR */ _Self& operator++() { _M_incr(); // 前进一个节点 return *this; } _Self operator++(int) { _Self __tmp = *this; _M_incr(); // 前进一个节点 return __tmp; } // 注意没有实现operator--,因为这是一个forward iterator }; template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) > class slist : private _Slist_base<_Tp,_Alloc> { __STL_CLASS_REQUIRES(_Tp, _Assignable); private: typedef _Slist_base<_Tp,_Alloc> _Base; public: typedef _Tp value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Slist_iterator<_Tp, _Tp&, _Tp*> iterator; typedef _Slist_iterator<_Tp, const _Tp&, const _Tp*> const_iterator; typedef typename _Base::allocator_type allocator_type; allocator_type get_allocator() const { return _Base::get_allocator(); } private: typedef _Slist_node<_Tp> _Node; typedef _Slist_node_base _Node_base; typedef _Slist_iterator_base _Iterator_base; _Node* _M_create_node(const value_type& __x) { _Node* __node = this->_M_get_node(); // 配置空间 __STL_TRY { construct(&__node->_M_data, __x); // 构造元素 __node->_M_next = 0; } __STL_UNWIND(this->_M_put_node(__node)); return __node; } public: explicit slist(const allocator_type& __a = allocator_type()) : _Base(__a) {} slist(size_type __n, const value_type& __x, const allocator_type& __a = allocator_type()) : _Base(__a) { _M_insert_after_fill(&this->_M_head, __n, __x); } explicit slist(size_type __n) : _Base(allocator_type()) { _M_insert_after_fill(&this->_M_head, __n, value_type()); } #ifdef __STL_MEMBER_TEMPLATES // We don't need any dispatching tricks here, because _M_insert_after_range // already does them. template <class _InputIterator> slist(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { _M_insert_after_range(&this->_M_head, __first, __last); } #else /* __STL_MEMBER_TEMPLATES */ slist(const_iterator __first, const_iterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { _M_insert_after_range(&this->_M_head, __first, __last); } slist(const value_type* __first, const value_type* __last, const allocator_type& __a = allocator_type()) : _Base(__a) { _M_insert_after_range(&this->_M_head, __first, __last); } #endif /* __STL_MEMBER_TEMPLATES */ slist(const slist& __x) : _Base(__x.get_allocator()) { _M_insert_after_range(&this->_M_head, __x.begin(), __x.end()); } slist& operator= (const slist& __x); ~slist() {} ... // 两个slist互换:只要将head交换互指即可。 void swap(slist& __x) { __STD::swap(this->_M_head._M_next, __x._M_head._M_next); } public: reference front() { return ((_Node*) this->_M_head._M_next)->_M_data; } const_reference front() const { return ((_Node*) this->_M_head._M_next)->_M_data; } // 从头部插入元素(新元素成为slist的第一个元素) void push_front(const value_type& __x) { __slist_make_link(&this->_M_head, _M_create_node(__x)); } void push_front() { __slist_make_link(&this->_M_head, _M_create_node()); } // 注意:没有push_back() // 从头部取走元素(删除之)。修改head void pop_front() { _Node* __node = (_Node*) this->_M_head._M_next; this->_M_head._M_next = __node->_M_next; destroy(&__node->_M_data); this->_M_put_node(__node); }
参考文献
STL源码剖析——侯捷
STL源码