C++之list模拟实现

C++之list模拟实现

一.介绍list

同vector一样都是容器,list底层:双向循环链表,由前驱指针、后继指针和数据组成,与vector不同于不是连续内存,vector是连续数组。

优点:任意位置插入,删除元素时间复杂度为O(1),erase删除时,仅仅被删除的节点迭代器失效,其余迭代器依旧有效

缺点:不支持下标访问,遍历效率低

二.list实现

1.list构造函数

2.list iterator

此处begin和end为正向迭代器(反向还莫有学),可进行++操作,迭代器向后移。

swap交换:先给自己一个头指针,再把需要交换的头指针给 给创建好的头指针,再把临时对象tmp的新头指针给原来的,完成交换。

为什么会有list类和list iterator类

list容器管整块链表数据,迭代器iterator专门管单个节点的访问、遍历,分工完全不一样,必须拆成两个类;

后者掌管:

1. 重载 * 解引用: *it 取出节点里存储的数据T

2. 重载 ++ 前置/后置自增: it++ 跳到下一个节点 _pNode = _pNode->_pNext

3. 重载 -- 自减:往前遍历上一个节点

4. 重载 == != :判断两个迭代器是否指向同一个节点

为什么要重载++,--:相较于vector,它空间是连续的,

1. vector迭代器本质就是封装的原生T*指针
vector内存连续,原生指针天然支持 ++ 、 -- 、 +n 、 [] 随机偏移:指针自增直接跳到下一个相邻元素。
所以不用手动重载 operator++ 、 operator-- ,直接复用原生指针自带的运算规则即可。

2. list不能用裸指针做迭代器,必须手动重载所有运算符
list节点零散分布在堆上,前后节点内存地址并不挨着。
单纯对节点Node*做 ++ ,只会走到这块内存后面随机地址,找不到下一个链表节点。
只能手动写重载

一、为啥三个模板参数
1. T :链表存的数据类型

2. Ref (引用)、 Ptr (指针):用来一套代码做出两种迭代器

- 普通迭代器: Ref=T&、Ptr=T* ,能读写数据

- const迭代器: Ref=const T&、Ptr=const T* ,只能读不能改
不用写两份重复代码,省事。

3. Self :给自己这个迭代器类起短别名,少写长名字。

二、各个函数为啥对应不同类型
1. Ref operator*() :解引用取值,用Ref控制能不能修改元素

2. Ptr operator->() :箭头访问成员,用Ptr控制读写权限

3. 拷贝构造、++运算符用 Self :指代迭代器本身类型,书写简单,方便链式运

总代码: