STL单链表slist简介
概述
slist(Single linked list)顾名思义,是一个单向链表,这个容器并不在标准规格之内,在我几年的代码学习生涯中也是第一次听说,既然侯老师的书中提到了,那也还是学习一蛤。
slist与list的主要差别是,前者的迭代器属于单向的Forward Iterator(可读写),后者的迭代器属于双向的Bidirectional Iterator(可以双向读写)。看起来slist的功能应该会不如list,但由于其单向链表的实现,其消耗的空间更小,某些操作更快。
回忆数据结构中在单链表的某个位置插入元素的过程,slist的底层实现就是单链表,因此会遇到我们曾经遇到过的麻烦:在某个位置插入时,必须要用一个指针从头到尾找到待插入位置的前一个位置。这便是在slist的一个大的缺点之一,因此,书中提到,在非起点位置使用insert或erase的算法是不智之举。
slist源码实现
在SGI STL源码中,slist的实现位于stl_slist.h
中
节点设计
容器的核心就是其底层存储于迭代器设计了,对于节点设计,使用了继承的关系,实际上简单的来说就是单链表的节点:指向下一个节点的指针和数据
代码实现如下:
//stl_slist.h
//单向链表的节点结构
struct _Slist_node_base
{
_Slist_node_base* _M_next;
};
//使用继承来实现单链表的节点结构:指针+数据
template <class _Tp>
struct _Slist_node : public _Slist_node_base
{
_Tp _M_data;
};
基于单链表的特性和节点的结构,源码中提供了不少内部全局函数,这些函数不对外开放的,仅仅在某些对外使用的接口实现中直接调用,例如:
//全局函数:单链表节点数,其实就是简单的遍历计数
inline size_t __slist_size(_Slist_node_base* __node)
{
size_t __result = 0;
for ( ; __node != 0; __node = __node->_M_next)
++__result;
return __result;
}
//全局函数:已知某一节点,插入新节点于其后
//返回插入节点之后的指针。
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;
__prev_node->_M_next = __new_node;
return __new_node;
}
迭代器设计
如上图所示,迭代器同样是使用了继承的方式:
//单向链表的迭代器基本结构
struct _Slist_iterator_base
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef forward_it