《STL源码剖析》chapter4 序列式容器之list

序列式容器list

list概述

STL中实现的list是数据结构中常提的双向环状链表。设计过list的人都知道,list本身和list所含的节点是不同的结构,需要分开设计。

其中STLlist的节点结构如下:

    //定义链表节点
    template<class T>
    struct __list_node{
        __list_node* prev;          //指向上一个节点
        __list_node* next;          //指向下一个节点
        T data;
    };
list的迭代器

list由于是双向链表,所以其迭代器应该是双向迭代器(BidirectionIterator),具有前移(++),后移(--)的能力。

下面以重载的++操作符为例进行说明:

    //前置++
    self& operator++(){
        node=(*node).next;
        return *this;
    }
    //后置++
    self operator++(int){
        self tmp=*this;
        node=(*node).next;
        return tmp;

其中后置版++通过设置一个int型参数与前置版本++进行区分,且后置版本返回的是一个,而前置版本返回的是一个引用。(关于c++的函数重载可以参考《C++ primer》chapter14 读书笔记

这里需要特别注意的是后置版本++中的self tmp=*this语句,这条语句首先调用的是iterator的拷贝构造函数ctor,并且以*this作为实参,而不是调用重载的operator*

以下是list迭代器的完整设计:

//定义链表迭代器
template<class T,class Ref,class Ptr>
struct __list_iterator{

    //下面两个声明其实作用是一样的,只是会为后面代码的可读性
    typedef __list_iterator<T,T&,T*>        iterator;
    typedef __list_iterator<T,Ref,Ptr>      self;

    //这里未继承iterator,所以显示定义迭代器的五种相应类别
    typedef T                               value_type;
    typedef Ptr                             pointer;
    typedef Ref                             reference;
    typedef ptrdiff_t                       difference_type;
    typedef wj::bidirectional_iterator_tag  iterator_category;

    typedef __list_node<T>* link_type;
    typedef size_t size_type;

    //指向一个链表节点
    link_type node;

    //定义ctor
    __list_iterator(){}
    __list_iterator(link_type x):node(x){}
    __list_iterator(const iterator& x):node(x.node){}

    //重载相关操作
    bool operator==(const iterator& x) const { return node==x.node; }
    bool operator!=(const iterator& x) const { return node!=x.node; }
    reference operator*() const { return (*node).data; }
    pointer operator->() const { return &(operator*()); }
    self& operator++(){
        node=(*node).next;
        return *this;
    }
    self operator++(int){
        self tmp=*this;
        node=(*node).next;
        return tmp;
    }
    self& operator--(){
        node=(*node).prev;
        return *this;
    }
    self operator--(int){
        self tmp=*this;
        node=(*node).prev;
        return tmp;
    }
};
list的数据结构

SGI STL中实现的不仅仅是一个双向链表,而且还是一个环状双向链表,其实现只利用了一个node指针。

node指针是一个占位用的指针,其next指针指向环状双向链表的头部,而其prev指针则指向环状双向链表的尾部。

template<class T,class Alloc=wj::alloc<__list_node<T>>>
class list{
    protected:
        typedef __list_node<T> list_node;
        //...
    public:
        typedef list_node* link_type;
        //...
    protected:
        //使用一个指针,便可表示整个环状双向链表
        link_type node;
        //...
};

从上述代码可以看出,SGI STL中的list仅使用一个指针便表示出整个链表,所以链表本身占用的空间只有4字节(32位机器)(但在后来的版本中链表有8字节)。

list的核心操作由插入insert,删除erase,迁移transfer(这里所谓的迁移操作,是将某连续范围的元素迁移到某个特定位置之前)等,大部分属于数据结构方面的知识,这里不再赘述。

最后

本节中涉及的代码及本人实现的toy级别的list可以参考github.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值