C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > STL容器list

STL容器之list源码详细解读

作者:DivineH

这篇文章主要介绍了STL容器之list源码详细解读,相对于vector的连续线性空间,list就显得更加复杂,它每插入或者删除一个元素,就配置或释放一个元素空间,需要的朋友可以参考下

简介

相对于vector的连续线性空间,list就显得更加复杂,它每插入或者删除一个元素,就配置或释放一个元素空间。

因此,list对于空间的利用非常精准,一点也不浪费,而且,对于任何位置的插入或者删除,list永远是常数时间。

构造函数

explicit list(const allocator_type& __a = allocator_type()) : _Base(__a) {}
// 构造拥有 n 个有值 value 的元素的容器
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()); }
// 构造拥有范围 [first, last) 内容的容器
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); }
// 拷贝构造函数
list(const list<_Tp, _Alloc>& __x) : _Base(__x.get_allocator())
{ insert(begin(), __x.begin(), __x.end()); }

对于list中的每一个节点,都被封装成了_List_node对象:

// 双向链表
struct _List_node_base {
  _List_node_base* _M_next;
  _List_node_base* _M_prev;
};

// list 节点
template <class _Tp>
struct _List_node : public _List_node_base {
  _Tp _M_data; // 节点存储的值
};

即list是通过双向循环链表来组织节点的。

主要函数

push_back

void push_back(const _Tp& __x) { insert(end(), __x); } // 插入一个节点,作为尾节点
// 在__position之前插入节点__x
iterator insert(iterator __position, const _Tp& __x) {
    _Node* __tmp = _M_create_node(__x);
    // 调整双向指针,插入新元素
    __tmp->_M_next = __position._M_node;  // list为双向链表
    __tmp->_M_prev = __position._M_node->_M_prev;
    __position._M_node->_M_prev->_M_next = __tmp;
    __position._M_node->_M_prev = __tmp;
    return __tmp;
}

push_back插入一个节点,作为尾结点,都是双向链表的常用操作,这里不再赘述。

push_front

void push_front(const _Tp& __x) { insert(begin(), __x); }  // 插入一个节点 __x,作为头结点
iterator insert(iterator __position, const _Tp& __x) {
    _Node* __tmp = _M_create_node(__x);
    // 调整双向指针,插入新元素
    __tmp->_M_next = __position._M_node;  // list为双向链表
    __tmp->_M_prev = __position._M_node->_M_prev;
    __position._M_node->_M_prev->_M_next = __tmp;
    __position._M_node->_M_prev = __tmp;
    return __tmp;
}

push_front同样是调用了insert(iterator, const _Tp&)来完成插入操作的。

clear

void clear() { _Base::clear(); }
template <class _Tp, class _Alloc>
void 
_List_base<_Tp,_Alloc>::clear() 
{
  _List_node<_Tp>* __cur = (_List_node<_Tp>*) _M_node->_M_next;  // 指向开始节点,begin()
  while (__cur != _M_node) {
    _List_node<_Tp>* __tmp = __cur;
    __cur = (_List_node<_Tp>*) __cur->_M_next;
    _Destroy(&__tmp->_M_data);  // 销毁(析构并释放)一个节点
    _M_put_node(__tmp);
  }
  // 恢复 _M_node 原始状态
  _M_node->_M_next = _M_node;
  _M_node->_M_prev = _M_node;
}

clear时从头结点到尾结点,依次释放每一个节点的内存空间。

特点

由于list是通过双向链表来实现的,它的迭代器要提供前移、后移的能力,所以list提供了Bidirectional iterator; 插入、删除节点的效率很高。

与vector的区别

到此这篇关于STL容器之list源码详细解读的文章就介绍到这了,更多相关STL容器list 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文