简介
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源码