STL源码剖析-序列式容器之list和slist

一.list

1.list概述

list是双向链表,对于任何位置的元素的插入或元素移除,list永远是常数时间.

2.list的节点

list本身和list节点是不同的数据结构,需要分开设计.STL list的节点结构:

    template <class T>  
    struct __list_node {  
      typedef void* void_pointer;  
      void_pointer next;  
      void_pointer prev;  
      T data;  
    };  

3.list的迭代器

STL list 是一格双向链表,迭代器必须具备前移,后移的能力,list提供的是Bidirectional Iterators.list的插入和删除操作都不会导致原来的list迭代器失效.

这里写图片描述

4.list的数据结构

STL list是一个环状双向链表,只需一个指针就可以表示整个链表.

template<class T,class Alloc = alloc> //缺省使用alloc为配置器
class list{  
protected :  
    typedef __list_node<T> list_node ;  
public  :  
    typedef list_node* link_type ;  
protected :  
    link_type node ; //只要一个指针,便可以表示整个环状双向链表  
};

如果让指针node指向刻意置于尾端的一个空白节点,node便能符合STL对于"前闭后开"区间的要求,成为last迭代器.

这里写图片描述

5.insert()函数

insert()是一个重载函数,最简单的一种如下:

    iterator insert(iterator position, const T& x){//在迭代器position所指位置插入一个节点,内容为x  
        link_type tmp = create_node(x);  
        tmp->next = position.node;  
        tmp->prev = position.node->prev;  
        (link_type(position.node->prev))->next = tmp;  
        return tmp;  
    }  

这里写图片描述

6.push_back()函数

将新元素插入list尾端,内部调用insert()函数

void push_back(const T& x){  
insert(end(),x);  
} 

7.push_front()函数

将新元素插入到list头端,内部调用insert()函数

    void push_front(const T&x){  
    insert(begin(),x);  
    }  

8.erase()函数

    iterator 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);  
    }

这里写图片描述

9.pop_front()函数

    void pop_front(){  
    erase(begin());  
    }  

10.pop_back()函数

移除尾节点,内部调用erase()函数

void pop_back(){  
iterator i=end();  
erase(--i);  
}

11.transfer()函数

将某连续范围的元素迁移到某个特定位置之前

void transfer(iterator position, iterator first, iterator last) {  
    if (position != last) {  
      (*(link_type((*last.node).prev))).next = position.node; //(1)  
      (*(link_type((*first.node).prev))).next = last.node;    //(2)  
      (*(link_type((*position.node).prev))).next = first.node;//(3)  
      link_type tmp = link_type((*position.node).prev);       //(4)  
      (*position.node).prev = (*last.node).prev;              //(5)  
      (*last.node).prev = (*first.node).prev;                 //(6)  
      (*first.node).prev = tmp;                               //(7)  
    }  
  }

这里写图片描述

二.slist

1.slist概述

SGI STL另提供一个单向链表slist.slist和list的主要差别在于,前者的迭代器属于单向的Forward Iterator,后者的迭代器属于双向的Bidirectional iterator

根据STL的习惯,插入操作会将新元素插入于指定位置之前.作为单向链表,slist没有任何方便的方法可以回头定出前一个位置,因此它必须从头找起.

2.slist的节点

这里写图片描述

3.slist的迭代器

这里写图片描述

4.slist的数据结构

    template<class T, class Alloc = alloc>  
    class slist  
    {  
    public :  
        typedef T   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<T,T&,T*> iterator ;  
        typedef __slist_iterator<T,const T&,const T*> const_iterator ;  

    private :  
        typedef __slist_node<T>   list_node ;  
        typedef __slist_node_base   list_node_base ;  
        typedef __slist_iterator_base   iterator_base ;  
        typedef simple_alloc<list_node,Alloc> list_node_allocator ;  

        static  list_node* create_node(const value_type& x)  
        {  
            list_node* node = list_node_allocator:;allocate() ; //配置空间  
            __STL_TRY{  
                construct(&node->data,x) ;  
                node->next = 0 ;  
            }  
            __STL_UNWIND(list_node_allocator:;deallocate(node)) ;  
            return node ;  
        }  

        static void destroy_node(list_node* node)  
        {  
            destroy(&node->data) ; //将元素析构     
            list_node_allocator::deallocate(node) ; //释放空间  
        }  

    private :  
        list_node_base head  ; //头部。注意,它不是指针,是实物  


    public:  
        slist() {head.next = 0 ;}   
        ~slist(){clear() ;}  

    public :  
        iterator begin() {return iterator((list_node*)head.next) ;}  
        iterator end() {return iteator(0) ;}  
        iterator size() {const __slist_size(head.next) ;}  
        bool empty() const {return head.next == 0 ;}   

        //两个slist互换:只要将head交换互指即可  
        void swap(slist &L)  
        {  
            list_node_base* tmp = head.next;  
            head.next = L.head.next ;  
            L.head.next = tmp ;  
        }  

    public :  
        //取头部元素  
        reference front() {return ((list_node*)head.next)->data ;}  

        //从头部插入元素(新元素成为slist的第一个元素)  
        void push_front(const value_type& x)  
        {  
            __slist_make_link(&head,create_node(x)) ;  
        }  

        //注意,没有push_back()  

        //从头部取走元素(删除之)。修改head  
        void pop_front()  
        {  
            list_node* node = (list_node*)head.next ;  
            head.next = node->next ;  
            destroy_node(node);  
        }  
        .....  
    }  ;  

5.slist的元素操作

这里写图片描述

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值