STL学习——Slist篇

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

你可能感兴趣的:(链表,STL,slist)