当前位置:网站首页>《STL 源码剖析》学习笔记之容器(二)list
《STL 源码剖析》学习笔记之容器(二)list
2022-07-29 18:08:00 【51CTO】
[图]The orange 2019-08-06
这是 herongwei 的第 83 篇原创
阅读本文大概需要 6.66 分钟
1、list 概述
相较于 vector 的连续线性空间,list 就显得复杂许多,它的好处是每次安插或删除一个元素,就配置或释放一个元素空间。因此,list 对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素安插或元素移除,list 永远是常数时间。
list 和 vector 是两个最常被使用的容器。什么时机下最适合使用哪一种容器,必须视元素的多寡、元素的构造复杂度、元素存取行为的特性而定。
list 结构定义
SGI list 不仅是一个双向串行,而且还是一个环状双向串行。所以它只需要一个指标,便可以完整表现整个串行:
安插一个元素之后的 list 状态如图 4-6。注意,安插完成后,新节点将位于标兵迭代器(标示出安插点)所指之节点的前方—这是 STL 对于「安插动作」的标准规范。
由于 list 不像 vector那样有可能在空间不足时做重新配置、数据搬移的动作,所以安插前的所有迭代器在安插动作之后都仍然有效。
2、几点注解
list 内部提供一个所谓的迁移动作(transfer):将某连续范围的元素迁移到某个特定位置之前。技术上很简单,节点间的指标移动而已。这个动作为其它的复杂动作如 splice, sort, merge 等奠定良好的基础。
1、node 是一个指针,SGI list 是一种双向环状链表,除了绿色的数据域本身之外,还要附带两个指针,一个往前指,一个往后指,也就是前驱指针和后继指针。
2、前驱和后继指针分别是 void_pointer 类型,看源码知道,void_pointer 是 void* 类型。原因?可见在程序后面操作要去转化类型。
3、list 的迭代器如何使用?链表是一种非连续的结构,所以迭代器不能是一种指针,但是我们还是要让迭代器要模拟指针的功能,也就是说,迭代器要足够聪明的知道,当用户要访问下一个元素的时候,迭代器要能够通过当前指向的位置的指针的 next 域,定位到正确访问的下一个位置,进去看 next 指针。
4、除了 array,vector 之外,所有的容器的迭代器必须是一种 class ,是一种智能指针,它才能设计出聪明的动作。
5、所有的容器必须要有一个 typedef xxx<T,T&,T> iterator 代表一种 class。有三个模板参数。
6、指针可能会被使用者进行怎样的操作呢?++,–,&,等等。
7、重载运算符 ++
调整迭代器的指向,使得指向当前结点的next结点
8、重载运算符 --也是一样
9、这里的两个返回值,一个返回 reference 一个不是,是为了模拟整数的这两种操作,在 C++ 中,两次前置++可以运行,但不允许两次后置++。
10、node 结点的取值操作,为什么这里要用.data 而不是直接用 -> ,这里有个原因在于为了让编译器区分后面的重载-> 运算符
11、所有容器遵循的设计原则是 前闭后开原则,在 list 里面,要把最后一个元素的下一个元素设置为不属于容器本身。因此,list 的设计刻意在环状尾端加一个空白结点。
12、在 G2.9 版 中 sizeof(list) = 4而在 G4.9 版 sizeof(list) = 8;
3、源码剖析
还记得之前的手写 LRU 吗?
我们知道,STL 中的 list 就是一种双向链表,我们在定义一个 cachesMap ,key 保存键,value 保存前面的 list 中指向双向链表实现的 LRU 的 Node 节点,也就是说 cachesMap 里面 每一个 value 对应的是一个双向链表的结点,那么具体访问的时候,利用迭代器就可以了,非常的方便。
LRU 的 Node 节点,也就是说 cachesMap 里面 每一个 value 对应的是一个双向链表的结点,那么具体访问的时候,利用迭代器就可以了,非常的方便。
这里,爱思考的同学们,看到上面的 splice 函数,不禁会思考,这个函数到底是如何实现的呢?本真刨根问底的精神,我们去探究一波 list 的源码吧。
先来看一张图片
没错了,上面的图示就是 splice 函数的实现过程,而在 list 里面,具体调用的则是 另外一个函数 transfer,下面是 transfer 的源码:
可以看到
第一步是调整 last 结点前一个结点的 next 指针;这样才能在调整 tmp 结点的 next 指针之后,将 first position 结点保存下来。
第二步是调整 first 结点的前一个结点的 next 指针;这样才能在调整 first 结点的 prev 指针之后,将 last 结点保存下来。
实际上,transfer 并非是一种公开的接口。list 公开提供的是所谓的接合动作(splice):将某连续范围的元素从一个 list 搬移到另一个(或同一个)list 的某个定点。
在来看一张比较形象的图片就大概知道了这个过程是怎么一回事了。
下面附上部分 list 源码。
参考资料:《STL源码剖析》(侯捷著)。
感兴趣的同学,欢迎有问题和我交流~
推荐阅读
《STL 源码剖析》学习笔记之容器(一)vector
认真的人,自带光芒!
原创不易
点个呗
边栏推荐
- 剖析Mooncake的代理原理,实现快速提效
- 【深度学习】YOLO转VOC VOC转YOLO
- [Code Hoof Set Novice Village 600 Questions] Find the square root of the given data
- The backslash \\ in MySQL is really a pit
- One's deceased father grind English vocabulary training camp Day 】 16 - bankrupt, remain, regulate, the construct and reflect
- macro definition small method
- 招聘|字节跳动云原生计算,期待你的加入
- [Operation and maintenance] ssh tunneling relies on the 22 port of ssh to realize the interface service of accessing the remote server
- LL(1),LR(0),SLR(1),LALR(1),LR(1)对比与分析
- 【7.23-7.29】博客精彩回顾
猜你喜欢
随机推荐
The service failure agent how to get things
The structure of the earth's over 200 million proteins is fully predicted, and AlphaFold detonates the "protein universe"
【回忆】奶奶的歌谣
Blender 源码分析(2)
开放原子开源基金会秘书长孙文龙:要打造以开发者为本的开源服务平台
A redis tool class to solve cache breakdown, cache penetration
EasyNVR更新版本至(V5.3.0)后页面不显示通道配置该如何解决?
【码蹄集新手村600题】求空间直角坐标系中俩点之间的距离
单核浏览器和双核浏览器有什么区别,哪个好用?
分批数据遍历的优化
Zigbee组网控制流程
KubeZoo:字节跳动轻量级多租户开源解决方案
One's deceased father grind English vocabulary training camp Day 】 16 - bankrupt, remain, regulate, the construct and reflect
AI 通过了图灵测试,科学家反应冷淡:“很棒,但没必要”
7行代码让B站崩溃3小时,竟因“一个诡计多端的0”
超声波传感器(CHx01) 学习笔记 Ⅲ-API介绍
国产钡铼分布式IO模块如何与西门子PLC Profinet通讯
[Deep Learning] YOLO to VOC VOC to YOLO
500强企业如何提升研发效能?来看看行业专家怎么说
SK海力士工厂发生氢氟酸泄漏,3名工人受伤!官方称不会影响生产