前言
在SGI STL中,list容器是一个循环的双向链表,它的内存空间效率较前文介绍的vector容器高。因为vector容器的内存空间是连续存储的,且在分配内存空间时,会分配额外的可用空间;而list容器的内存空间不一定是连续存储,内存之间是采用迭代器或节点指针进行连接,并且在插入或删除数据节点时,就配置或释放一个数据节点,并不会分配额外的内存空间,这两个操作过程都是常数时间。
与vector容器不同的是,list容器在进行插入操作或拼接操作时,迭代器并不会失效;且不能以普通指针作为迭代器,因为普通指针的+或-操作只能指向连续空间的后移地址或前移个地址,不能保证指向list的下一个节点,迭代器必须是双向迭代器,因为list容器具备有前移和后移的能力。
注:本文所列的源码出自SGI STL中的文件<stl_list.h>,对于list容器类的详细信息也可以查看《list容器库》和《MSDN的list类》
list容器
list节点和list数据结构
在list容器中,list本身和list节点是分开设计的,list节点结构是存储数据和指向相邻节点的指针;如下源码所示:
//以下是list链表节点的数据结构
struct _List_node_base {
_List_node_base* _M_next;//指向直接后继节点
_List_node_base* _M_prev;//指向直接前驱节点
};
template <class _Tp>
struct _List_node : public _List_node_base {
_Tp _M_data;//节点存储的数据
};
list
本身的数据结构是只有一个指向链表节点的指针,因为
list
容器是循环双向链表,则足够遍历整个链表;如下源码所示:
//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {
...
public:
typedef _List_node<_Tp> _Node;
protected:
//定义指向链表节点指针
_List_node<_Tp>* _M_node;
...
};
下面给出
list节点和list本身的数据结构图:
list容器的迭代器
list容器的内存空间存储不一定是连续的,则不能用普通指针做为迭代器;list容器的迭代器是双向迭代器,这也是导致list容器的排序成员函数sort()不能使用STL算法中的排序函数,因为STL中的排序算法接受的迭代器是随机访问迭代器;list容器在进行插入和拼接操作时迭代器不会失效;以下是源码对迭代器的定义:
//以下是链表List_iterator_base的迭代器
struct _List_iterator_base {
//数据类型
typedef size_t size_type;
typedef ptrdiff_t difference_type;
//list迭代器的类型是双向迭代器bidirectional_iterator
typedef bidirectional_iterator_tag iterator_category;
//定义指向链表节点的指针
_List_node_base* _M_node;
//构造函数
_List_iterator_base(_List_node_base* __x) : _M_node(__x) {}
_List_iterator_base() {}
//更新节点指针,指向直接前驱或直接后继节点
void _M_incr() { _M_node = _M_node->_M_next; }
void _M_decr() { _M_node = _M_node->_M_prev; }
//操作符重载
bool operator==(const _List_iterator_base& __x) const {
return _M_node == __x._M_node;
}
bool operator!=(const _List_iterator_base& __x) const {
return _M_node != __x._M_node;
}
};
//以下是链表List_iterator的迭代器
template<class _Tp, class _Ref, class _Ptr>
struct _List_iterator : public _List_iterator_base {
typedef _List_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
typedef _List_iterator<_Tp,_Ref,_Ptr> _Self;
typedef _Tp value_type;
typedef _Ptr pointer;
typedef _Ref reference;
typedef _List_node<_Tp> _Node;
//构造函数
_List_iterator(_Node* __x) : _List_iterator_base(__x) {}
_List_iterator() {}
_List_iterator(const iterator& __x) : _List_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++() {
this->_M_incr();
return *this;
}
_Self operator++(int) {
_Self __tmp = *this;
this->_M_incr();
return __tmp;
}
_Self& operator--() {
this->_M_decr();
return *this;
}
_Self operator--(int) {
_Self __tmp = *this;
this->_M_decr();
return __tmp;
}
};
#ifndef __STL_CLASS_PARTIAL_SPECIALIZATION
//返回迭代器的类型
inline bidirectional_iterator_tag
iterator_category(const _List_iterator_base&)
{
return bidirectional_iterator_tag();
}
template <class _Tp, class _Ref, class _Ptr>
inline _Tp*
value_type(const _List_iterator<_Tp, _Ref, _Ptr>&)
{
return 0;
}
inline ptrdiff_t*
distance_type(const _List_iterator_base&)
{
return 0;
}
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
list容器的构造函数和析构函数
这里把list容器的构造函数列出来讲解,使我们对list容器的构造函数进行全面的了解,以便我们对其使用。在以下源码的前面我会总结出list容器的构造函数及其使用方法。
//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {
...
public:
//**********************************************************************
/***********************以下是构造函数**********************************
//*******************默认构造函数***************************************
explicit list( const Allocator& alloc = Allocator() );
//**********************具有初值和大小的构造函数************************
explicit list( size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
list( size_type count,
const T& value,
const Allocator& alloc = Allocator());
//**************只有大小的构造函数**************************************
explicit list( size_type count );
//************某个范围的值为初始值的构造函数****************************
template< class InputIt >
list( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
//************拷贝构造函数***********************************************
list( const list& other );
*/
//**********************************************************************
//构造函数
//链表的默认构造函数
explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}
list(size_type __n, const _Tp& __value,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ insert(begin(), __n, __value); }
explicit list(size_type __n)
: _Base(allocator_type())
{ insert(begin(), __n, _Tp()); }
#ifdef __STL_MEMBER_TEMPLATES
// We don't need any dispatching tricks here, because insert does all of
// that anyway.
template <class _InputIterator>
list(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ insert(begin(), __first, __last); }
#else /* __STL_MEMBER_TEMPLATES */
list(const _Tp* __first, const _Tp* __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ this->insert(begin(), __first, __last); }
list(const_iterator __first, const_iterator __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ this->insert(begin(), __first, __last); }
#endif /* __STL_MEMBER_TEMPLATES */
list(const list<_Tp, _Alloc>& __x) : _Base(__x.get_allocator())
{ insert(begin(), __x.begin(), __x.end()); }//拷贝构造函数
~list() { }//析构函数
//赋值操作
list<_Tp, _Alloc>& operator=(const list<_Tp, _Alloc>& __x);
//构造函数,析构函数,赋值操作 定义到此结束
//*******************************************************************
...
};
list容器的成员函数
list容器的成员函数为我们使用该容器提供了很大的帮助,所以这里对其进行讲解,首先先给出源码的剖析,然后在对其中一些重点的成员函数进行图文讲解;具体源码剖析如下所示:
//以下是双向链表list类的定义,分配器_Alloc默认为第二级配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class list : protected _List_base<_Tp, _Alloc> {
// requirements:
...
protected:
//创建值为x的节点,并返回该节点的地址
_Node* _M_create_node(const _Tp& __x)
{
_Node* __p = _M_get_node();//分配一个节点空间
__STL_TRY {//把x值赋予指定的地址,即是data值
_Construct(&__p->_M_data, __x);
}
__STL_UNWIND(_M_put_node(__p));
return __p;//返回节点地址
}
//创建默认值的节点
_Node* _M_create_node()
{
_Node* __p = _M_get_node();
__STL_TRY {
_Construct(&__p->_M_data);
}
__STL_UNWIND(_M_put_node(__p));
return __p;
}
public:
//以下是迭代器的定义
iterator begin() { return (_Node*)(_M_node->_M_next); }
const_iterator begin() const { return (_Node*)(_M_node->_M_next); }
iterator end() { return _M_node; }
const_iterator end() const { return _M_node; }
reverse_iterator rbegin()
{ return re