STL容器之list源码详细解读

 更新时间:2024年01月03日 09:10:42   作者: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的区别

  • vector为存储的对象分配一块连续的地址空间,随机访问效率很高。但是插入和删除需要移动大量的数据,效率较低。尤其当vector中存储的对象较大,或者构造函数复杂,则在对现有的元素进行拷贝的时候会执行拷贝构造函数。
  • list中的对象是离散的,随机访问需要遍历整个链表,访问效率比vector低。但是在list中插入元素,尤其在首尾插入,效率很高,只需要改变元素的指针。
  • vector是单向的,而list是双向的;
  • 向量中的iterator在使用后就释放了,但是链表list不同,它的迭代器在使用后还可以继续用;链表特有的;

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

相关文章

  • 通过代码实例解析c++ vector常用方法

    通过代码实例解析c++ vector常用方法

    这篇文章主要介绍了通过代码实例解析c++ vector常用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • C++实现LeetCode(120.三角形)

    C++实现LeetCode(120.三角形)

    这篇文章主要介绍了C++实现LeetCode(120.三角形),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言实现简单回声服务器

    C语言实现简单回声服务器

    这篇文章主要为大家详细介绍了C语言实现简单回声服务器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++深入浅出探索数据结构的原理

    C++深入浅出探索数据结构的原理

    C++的数据结构很多,很复杂,所以本文将通过示例带大家深入了解一下C++中的数据结构与算法。文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-05-05
  • C语言实现循环单链表的示例代码

    C语言实现循环单链表的示例代码

    这篇文章主要给大家详细介绍了C语言如何实现循环单链表,文章通过代码示例讲解的非常详细,对我们的学习或工作有一定的参考价值,感兴趣的小伙伴跟着小编一起来看看吧
    2023-08-08
  • C/C++ 中memset() 函数详解及其作用介绍

    C/C++ 中memset() 函数详解及其作用介绍

    这篇文章主要介绍了C/C++ 中memset() 函数详解及其作用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 利用Matlab绘制甘特图的方法详解

    利用Matlab绘制甘特图的方法详解

    这篇文章主要为大家详细介绍了如何利用Matlab实现甘特图(gantt chart)的绘制,文中的示例代码讲解详细,对我们学习Matlab有一定帮助,需要的可以参考一下
    2022-10-10
  • C++实现自顶向下的归并排序算法

    C++实现自顶向下的归并排序算法

    这篇文章主要介绍了C++实现自顶向下的归并排序算法,结合实例详细分析了自顶向下的归并排序算法的原理与具体实现步骤,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-12-12
  • C++中的memset用法详解

    C++中的memset用法详解

    memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值,本文给大家介绍C++中的memset用法,感兴趣的朋友跟随小编一起看看吧
    2023-02-02
  • C++设计模式之抽象工厂模式

    C++设计模式之抽象工厂模式

    这篇文章主要介绍了C++设计模式之抽象工厂模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07

最新评论