C++ -- list

一.lisit的介绍

1.list是属于STL的一部分,list可以在链表中的任意位置进行插入和删除操作的序列式容器,并且这个容器可以前后双向迭代,这是由于双向循环链表的特殊性。

2.list的底层是带头双向循环链表结构,双向链表中的每个元素都存在不同的节点之中,所以它的迭代器并不能通过普通的指针进行实现,而是需要通过它的next指向和prev指向来模拟迭代器。

3.list优势是可以在任意地方进行O(1)的时间复杂度进行插入,移除,这是因为它每个节点独立出来的特点。但是也正因如此,它的查改排序效率是低下的,它并不能像vector一样用下标访问数据,每次都需要遍历链表。

4.与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素。

二.list的使用

以下展示一些list的重要接口,我们学习能够熟练使用这些接口就能够掌握链表l

|---------------------------------------------------------------|--------------------------------------------------|
| 构造函数 | 接口说明 |
| list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的元素 |
| list() | 构造空的****list |
| list (const list& x) | 拷贝构造函数 |
| list (InputIterator first, InputIterator last) | **[first, last)区间中的元素构造list** |

list迭代器的使用

|-------------|-----------------------------------------------------------------------------------------------------------------|
| 函数声明 | 接口说明 |
| begin end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
| rbegin rend | 返回第一个元素的reverse_iterator,end位置返回最后一个元素下一个位置的reverse_iterator,begin位置 |

1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

list容量函数

|-----------|------------------------------------------------------|
| 函数声明 | 接口说明 |
| empty | 检测list是否为空,是返回true,否则返回****false |
| size | 返回list中有效节点的个数 |

list操作函数

|----------------|------------------------------------------|
| 函数声明 | 接口说明 |
| push_front | list首元素前插入值为val的元素 |
| pop_front | 删除list中第一个元素 |
| push_back | list尾部插入值为val的元素 |
| pop_back | 删除list中最后一个元素 |
| insert | list position位置中插入值为****val |
| erase | 删除list position位置的元素 |
| swap | 交换两个list中的元素 |
| clear | 清空list中的有效元素 |

三.list的模拟实现

1.首先定义节点类

2.定义迭代器类

这里使用了三个模板参数是为了在list外部构建迭代器的时候能够通过传const或者非const类型的参数构建const或者非const迭代器。

迭代器具体实现

可以看到这里对迭代器的一些常见操作进行了重载,因为list节点独立的特殊性,我们需要对这些操作进行特殊处理。

3.list类具体实现

list类中只有一个头节点和size大小。构造这里没有实现其他复杂的,头节点用ListNode的默认构创建。

迭代器接口

插入删除操作

这里需要注意的是插入删除以后要返回一个迭代器,因为原来的迭代器插入操作过后在逻辑上已经是失效的了,删除时这个节点直接没有了。

四.list与vector的对比

list和vector的底层结构不同,导致特性以及应用场景大不相同

|-------------------------------|----------------------------------------------------------------------------------------|-------------------------------------------------------|
| | vector | list |
| | 动态顺序表,一段连续空间 | 带头结点的双向循环链表 |
| 访 | 支持随机访问,访问某个元素效率O(1) | 不支持随机访问,访问某个元素 效率****O(N) |
| | 任意位置插入和删除效率低,需要搬移元素,时间复杂O(N),插入时有可能需要增容,容:开辟新空间,拷贝元素,释放旧空间,导致效率更低 | 任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1) |
| | 底层为连续空间,不容易造成内存碎片,空间利用率****高,缓存利用率高 | 底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低 |
| | 原生态指针 | 对原生态指针
(节点指针)进行封装 |
| | **在插入元素时,要给所有的迭代器重新赋值,因为插入
元素有可能会导致重新扩容,致使原来迭代器失效,删
**除时,当前迭代器需要重新赋值否则会失效
| 插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响 |
| 使 | 需要高效存储,支持随机访问,不关心插入删除效率 | 大量插入和删除操作,不关心随****机访问 |

相关推荐
心平气和量大福大32 分钟前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa1 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行1 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
噢,我明白了2 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
mabing9933 小时前
Qt 生成条纹图
开发语言·qt
蓝悦无人机3 小时前
C++基础 — 函数总结
开发语言·c++
糖果店的幽灵3 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph
Fu_Lin_3 小时前
Qt 嵌入式从零基础到精通总纲
开发语言·qt·嵌入式·qt嵌入式