STL源码剖析 slist单向链表概述

本文详细介绍了STL中单向链表slist的实现细节,包括节点结构、迭代器实现以及相关操作如插入、删除等。slist与双向链表的主要区别在于其迭代器为单向ForwardIterator,不支持反向遍历。在内存管理和效率方面,slist具有一定的优势,但插入和删除操作需要注意。此外,文章还展示了slist迭代器的内部结构和操作方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

  • SGI STL的list是一个双向链表,单向链表是slist,其不在标准规格之内
  • 单向和双向链表的区别在于,单向链表的迭代器是单向的 Forward Iterator,双向链表的迭代器属于双向的Bidirectional Iterator。因此很多功能都被受限
  • 但是单向链表的耗用的空间更小,某些操作更快
  • 注意事项:插入操作会将新的元素插入到指定的位置之前,而不是之后的位置。但是单向链表无法回头确定前一个位置,因此需要从头部开始重新找起,即 除了在单向链表的起始处附近其余的地方进行insert 或者 erase都是不合适的操作。这也是单向和双向链表之间最大的差异,因此 单向链表提供了 insert_after() 和 erase_after() 供灵活使用
  • 基于上述的考虑,slist 也不提供push_back() 只提供push_front(),因此一定要注意单向链表元素的顺序和 元素的插入进来的顺序 相反

slist的节点

  • 单向链表的迭代器比双向链表更为复杂一些,运用了继承关系,因此在型别转换层面上有着复杂的表现

#include <iostream>

//单向链表的节点的基本结构
struct __slist_node_base{
    __slist_node_base* next;
};

//单向链表的节点结构
template <class T>
struct __slist_node : public __slist_node_base{
    T data;
};

//全局函数 已知某一个节点,插入新的节点于其后
inline __slist_node_base* __slist_make_link(
        __slist_node_base* prev_node,__slist_node_base* new_node){
    //令new_node节点的下一个节点为prev节点的下一节点
    new_node->next = prev_node->next->next;
    prev_node->next = new_node; //令prev节点的next指针指向new节点
    return new_node;
}

//全局函数 单向链表的大小(元素的个数)
inline std::size_t __slist_size(__slist_node_base* node){
    std::size_t result = 0;
    for( ; node != 0;node = node->next){
        ++result; //一个一个累计
    }
    return result;
}

slist的迭代器

  •  实际构造的时候 注意迭代器和节点之间的关系
//单向链表的迭代器的基本结构
struct __slist_iterator_base{
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef std::forward_iterator_tag iterator_category; //注意 单向

    __slist_node_base* node; //指向节点的基本结构 next指针

    __slist_iterator_base(__slist_node_base* x): node(x){}

    void incr(){node = node->next; } //前进一个节点

    bool operator==(const __slist_iterator_base& x)const{
        return node == x.node;
    }

    bool operator!=(const __slist_iterator_base& x)const{
        return node != x.node;
    }
};

//单向链表的迭代器结构
template <class T,class Ref,class Ptr>
struct __slist_iterator : public __slist_iterator_base{
    typedef __slist_iterator<T,T&,T*>  iterator;
    typedef __slist_iterator<T,const T&,const T*>const_iterator;
    typedef __slist_iterator<T,T&,T*>  self;

    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __slist_node<T> list_node;

    //调用slist<T>::end()会造成__slist_iterator(0) 于是调用如下函数
    __slist_iterator(list_node* x) : __slist_iterator_base(x){}
    __slist_iterator(): __slist_iterator_base(0){}
    __slist_iterator(const iterator& x): __slist_iterator_base(x.node){}

    reference operator*() const {return ((list_node*)node)->data;}
    reference operator->() const {return &(operator*());}

    self& operator++(){
        incr(); //前进一个节点
        return *this;
    }

    self& operator++(int){
        self tmp = *this;
        incr(); //前进一个节点
        return tmp;
    }
    //没有实现operator-- 因为这是一个单向链表,使用的是forward iterator
};
  • 注意比较两个slist迭代器是否等同时,比如常规循环下需要判断 迭代器是否等同于 slist.end() 
  • 但是__slist_iterator并没有对operator==进行重载,所以会调用 __slist_iterator_base::operator== ,__slist_iterator_base::operator==内部通过判定 __slist_iterator_base* node来判定两个迭代器是否等同

slist的数据结构

#include <iostream>

//单向链表的节点的基本结构
struct __slist_node_base{
    __slist_node_base* next;
};

//单向链表的节点结构
template <class T>
struct __slist_node : public __slist_node_base{
    T data;
};

//全局函数 已知某一个节点,插入新的节点于其后
inline __slist_node_base* __slist_make_link(
        __slist_node_base* prev_node,__slist_node_base* new_node){
    //令new_node节点的下一个节点为prev节点的下一节点
    new_node->next = prev_node->next->next;
    prev_node->next = new_node; //令prev节点的next指针指向new节点
    return new_node;
}

//全局函数 单向链表的大小(元素的个数)
inline std::size_t __slist_size(__slist_node_base* node){
    std::size_t result = 0;
    for( ; node != 0;node = node->next){
        ++result; //一个一个累计
    }
    return result;
}

//单向链表的迭代器的基本结构
struct __slist_iterator_base{
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef std::forward_iterator_tag iterator_category; //注意 单向

    __slist_node_base* node; //指向节点的基本结构 next指针

    __slist_iterator_base(__slist_node_base* x): node(x){}

    void incr(){node = node->next; } //前进一个节点

    bool operator==(const __slist_iterator_base& x)const{
        return node == x.node;
    }

    bool operator!=(const __slist_iterator_base& x)const{
        return node != x.node;
    }
};

//单向链表的迭代器结构
template <class T,class Ref,class Ptr>
struct __slist_iterator : public __slist_iterator_base{
    typedef __slist_iterator<T,T&,T*>  iterator;
    typedef __slist_iterator<T,const T&,const T*>const_iterator;
    typedef __slist_iterator<T,T&,T*>  self;

    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __slist_node<T> list_node;

    //调用slist<T>::end()会造成__slist_iterator(0) 于是调用如下函数
    __slist_iterator(list_node* x) : __slist_iterator_base(x){}
    __slist_iterator(): __slist_iterator_base(0){}
    __slist_iterator(const iterator& x): __slist_iterator_base(x.node){}

    reference operator*() const {return ((list_node*)node)->data;}
    reference operator->() const {return &(operator*());}

    self& operator++(){
        incr(); //前进一个节点
        return *this;
    }

    self& operator++(int){
        self tmp = *this;
        incr(); //前进一个节点
        return tmp;
    }
    //没有实现operator-- 因为这是一个单向链表,使用的是forward iterator
};

template<class T,class Alloc>
class simple_alloc{
public:
    static T* allocate(std::size_t n){
        return 0==n?0:(T*)Alloc::allocate(n * sizeof(T));
    }
    static T* allocate(void){
        return (T*)Alloc::allocate(sizeof (T));
    }

    static void deallocate(T* p,size_t n){
        if (n!=0){
            Alloc::deallocate(p,n * sizeof(T));
        }
    }
    static void deallocate(T* p){
        Alloc::deallocate(p,sizeof(T));
    }
};

#ifdef __STL_USE_EXCEPTIONS
#define __STL_TRY   try
#define __STL_UNWIND(action)   catch(...) { action; throw; }
#else
#define __STL_TRY
#define __STL_UNWIND(action)
#endif

namespace Chy{
    template <class T>
    inline T* _allocate(ptrdiff_t size,T*){
        std::set_new_handler(0);
        T* tmp = (T*)(::operator new((std::size_t)(size * sizeof (T))));
        if (tmp == 0){
            std::cerr << "out of memory" << std::endl;
            exit(1);
        }
        return tmp;
    }

    template<class T>
    inline void _deallocate(T* buffer){
        ::operator delete (buffer);
    }

    template<class T1,class T2>
    inline void _construct(T1 *p,const T2& value){
        new(p) T1 (value);  //没看懂
    }

    template <class T>
    inline void _destroy(T* ptr){
        ptr->~T();
    }

    template <class T>
    class allocator{
    public:
        typedef T           value_type;
        typedef T*          pointer;
        typedef const T*    const_pointer;
        typedef T&          reference;
        typedef const T&    const_reference;
        typedef std::size_t size_type;
        typedef ptrdiff_t   difference_type;

        template<class U>
        struct rebind{
            typedef allocator<U>other;
        };

        pointer allocate(size_type n,const void * hint = 0){
            return _allocate((difference_type)n,(pointer)0);
        }

        void deallocate(pointer p,size_type n){
            _deallocate(p);
        }

        void construct(pointer p,const T& value){
            _construct(p,value);
        }

        void destroy(pointer p){
            _destroy(p);
        }

        pointer address(reference x){
            return (pointer)&x;
        }

        const_pointer const_address(const_reference x){
            return (const_pointer)&x;
        }

        size_type max_size()const{
            return size_type(UINT_MAX/sizeof (T));
        }
    };
}

template <class T,class 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 std::size_t size_type;
    typedef std::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{
            Chy::allocator<T>::construct(&node->data,x);
            node->next = 0;
        };
        __STL_UNWIND(list_node_allocator::deallocate(node);) //释放空间
    }

    static void destroy_node(list_node* node){
        Chy::allocator<T>::destroy(&node->data);//将元素析构
        list_node_allocator::deallocate(node);  //释放空间
    }
private:
    list_node_base head; //头部 注意head不是指针,是事物
public:
    slist(){head.next = 0;}
    ~slist(){clear();}
public:
    void clear(){
        erase_after(&head,0);
    }
    //全局函数 传递链表的头部和尾部
    inline list_node_base* erase_after(list_node_base* before_first,
                                       list_node_base* last_node){
        list_node * cur = (list_node*)(before_first->next);
        while (cur != last_node){
            list_node * tmp = cur;
            cur = (list_node *)cur->next;
            destroy_node(tmp);
        }
        before_first->next = last_node;
        return last_node;
    }
public:
    iterator begin(){return iterator((list_node*)head.next);}
    iterator end(){return iterator(0);}
    size_type size() const{return __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;
    }
    //获取头部元素
    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);
    }

};

元素操作

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值