4.9.1 slist概述
在STL标准中提供了双向链表list,本文介绍的是SGISTL中<stl_slist.h>定义的单向链表slist。单向链表的迭代器是属于正向迭代器,所以在单链表进行插入元素时,在指定节点之后插入时时间是常数O(1),在指定节点之前插入时需要线性时间O(n)。相比于双向链表list,它所耗用的空间更小,某些操作更快。slist和list有一个共同的特殊是:它们的插入,移除,拼接等操作不会造成原有的迭代器失效。
根据STL的习惯,插入操作会将新元素插入于指定位置之前,作为单向链表,slist不能回头定出前一个位置,因此它必须从头找起。为此,slist特别提供了insert_after() 和erase_after()供灵活使用。同理,slist只提供push_front()。
4.9.2 slist的节点
slist的节点结构只有存储节点数据和指向下一个节点的指针。
//单向链表的节点基本结构
struct _Slist_node_base
{
_Slist_node_base* _M_next;
};
//单向链表节点结构
template <class _Tp>
struct _Slist_node : public _Slist_node_base
{
_Tp _M_data;
};
4.9.3 slist的迭代器
由于slist是单向链表,所以只提供正向迭代器,若要查找指定节点的前一个节点时,operator--不能使用,只能从头遍历,但是可以operator++和operator*操作;
//单向链表的迭代器的基本结构
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_iterator() : _Slist_iterator_base(0) {}
_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 */
//前缀operator++
_Self& operator++()
{
_M_incr();
return *this;
}
//后缀operator++
_Self operator++(int)
{
_Self __tmp = *this;
_M_incr();
return __tmp;
}
//单向链表不能operator--操作
};
4.9.4 slist的数据结构
slist单向链表只需要给出该链表的头部head,便可以通过head->next遍历该链表;
typedef simple_alloc<_Slist_node<_Tp>, _Alloc> _Alloc_type;
_Slist_node<_Tp>* _M_get_node() { return _Alloc_type::allocate(1); }
void _M_put_node(_Slist_node<_Tp>* __p) { _Alloc_type::deallocate(__p, 1); }
_Slist_node_base* _M_erase_after(_Slist_node_base* __pos)
{
_Slist_node<_Tp>* __next = (_Slist_node<_Tp>*) (__pos->_M_next);
_Slist_node_base* __next_next = __next->_M_next;
__pos->_M_next = __next_next;
destroy(&__next->_M_data);
_M_put_node(__next);
return __next_next;
}
_Slist_node_base* _M_erase_after(_Slist_node_base*, _Slist_node_base*);
protected:
_Slist_node_base _M_head;
};
//单向链表slist定义
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class slist : private _Slist_base<_Tp,_Alloc>
{
// requirements:
__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;
private:
typedef _Slist_node<_Tp> _Node;
typedef _Slist_node_base _Node_base;
typedef _Slist_iterator_base _Iterator_base;
...
};