list-

insert使用注意

list无法像vector的迭代器指向连续的空间,所以只能手动的去++it,循环到第五个位置(i=5)
在这里插入图片描述

list的迭代器失效问题

insert后it仍然指向原来结点,所以不存在失效问题
在这里插入图片描述

erase后it指向的结点不存在了,就存在失效问题,和vector一样erase设计了返回值返回删除的下一个结点迭代器
在这里插入图片描述

迭代器的分类

性质(容器底层结构决定)

单向 ++ 单链表 forward_list / 哈希 unordered_xxx
双向 ++ / - - 双向循环带头链表(list) / map / set
随机 ++ / - - / + / - vector / string / deque

在这里插入图片描述
InputIterator 更期望你用单向
Bidirectionaliterator 期望双向
Random 期望随机迭代器
他们具有兼容的性质
随机是特殊的双向,因此vector 的迭代器可以使用reverse

list里提供了reverse,算法库里也有reverse,这个接口提供的有点多余
但是list里面的sort提供的不多余,因为算法里面的sort是快排需要随机迭代器,而list不支持,所以单独提供。
但是list提供的sort意义同样有限,因为如果需要大量数据进行排序,一定是要把数据放到可以支持快排的容器中,list的sort底层用的是归并,这个接口的提供适合少量数据的排序,很方便,但是大量的数据效率不如快排,所以这个接口不提供也没什么,提供了反而会误导你直接使用list的sort

模板回顾

预备知识:
普通类,类名和类型是一样
类模板,类名和类型不一样
类名: Stack
类型: Stack< T >

构造函数的函数名 = 类名

stack< T >是类型,指定类域用类型

在写class list时
在类型重命名时注意不要写错类名和类型,常常会写成 typedef list_node Node
在这里插入图片描述
为什么list里面有那么多typedef?
因为模板的加入类型变得很长,类型重命名更加方便

list底层实现

先要有一个结点类型,自然是模板类,val保存T类型数据
在这里插入图片描述

list类中成员变量很简单,就是一个头指针指向哨兵结点,或者再多个size记录结点个数。
在这里插入图片描述

在这里插入图片描述

迭代器

迭代器模拟的是指针,所有的容器都提供一个像指针一样的方式去访问容器,迭代器可能是原生指针,但不一定都是原生指针
我们模拟实现vector用的是原生指针,但vs设计的vector都不是原生指针,而是用类去封装原生指针重载operator*() operator++()等,这样才可以检查erase后迭代器失效的问题
迭代器不暴露底层实现容器的结构细节,迭代器提供了统一的方式去访问各种底层结构,顺序表,链表,树等。并且一些公共的算法也可以用迭代器的方式去访问,就可以把算法提取出来,那就不用重复再去写
迭代器的底层都逃不开指针

list的迭代器能不能用 typedef Node* iteraotr ,也就是结点的指针充当迭代器?
在这里插入图片描述
答:
在这里插入图片描述

不能,vector中迭代器typedef T* iterator,指向T类型对象,解引用就可以拿到T对象
Node* 结点指针解引用拿到的是结点,而我想要的是结点里面的数据
Node* 如果++ 充当迭代器无法到达下一个结点,因为list结点底层不连续!
而vector的迭代器是原始指针指向连续空间,自然可以++

如何解决?再定义一个类型,底层封装结点指针,利用运算符重载完成迭代器相应功能。
精华
链表的迭代器还能不能用内置类型结点的指针?不能,但是结点的指针还是数据基础
库里用 list_iterator的类去封装结点的指针,利用运算符重载对这个类对象的++,或者解引用,去调用重载函数,++就是结点指针往后走到下一个结点,
解引用就是返回结点指针指向的val
在这里插入图片描述

也就是说用一个结点的指针就可以构造一个迭代器Iterator
在这里插入图片描述

迭代器的使用

单参数构造函数支持隐式类型转换

知识回顾
可以直接 return _head->-next 或者 iterator(_head->_next)
在这里插入图片描述
返回的迭代器指向如下所示
在这里插入图片描述

类中定义的类型

  1. typedef 定义的类型 内嵌类型
  2. 内部类
    在这里插入图片描述

定义Node 是给list类域中自己使用的,所以是私有
迭代器要公有,因为外部要使用
在这里插入图片描述

并不是赋值重载而是拷贝构造

在这里插入图片描述

如何设计const迭代器?

预备知识
迭代器和const迭代器
在这里插入图片描述

问题:能不能如下设计const迭代器?
在这里插入图片描述
答:不能
根据const迭代器期望解引用不能被修改,所以const迭代器模拟的是const T* ptr1的行为(禁止解引用但可以++)
如果是 const list_iterator const_iterator的话,const修饰list_iterator 则迭代器本身不能被修改,也就不能++,因为++会修改成员变量
()

那该如何设计?
期待不能解引用,那么将operator*()的返回值改为const T& operator*()即可,并且此时需要两个迭代器的类,只是operator*()函数的返回值不一样,一个加const,一个不加,但是这样设计太冗余了,如果学过模板,那么模板可以帮我们做到这一点

在这里插入图片描述

在这里插入图片描述

利用模板还是生成2个不同的类,就像vector 和 vector 一样,这里就是list_iterator<T,T&> 和 list_iterator<T,const T&>
原来我们手动写2个类的工作,利用模板交给了编译器去做。
在这里插入图片描述

迭代器类型重定义

在这里插入图片描述

迭代器类第三个模板参数

operator->( )的省略->

为什么迭代器要重载->呢?
因为迭代器仿的是指针,指针有→,那么迭代器也要有
在链表中保存的数据是结构体时,要访问结构体的数据可以重载<<,或者直接迭代器解引用拿到结构体本身(it)._a1,迭代器重载箭头就和原生指针一样直接→访问了!
但是为什么说省略了一个→,因为图中看到it->_a2在进行it.operator->()后返回的A
后面直接跟_a2,
it->->_a2才是符合语法,这里编译器特殊处理,可以省略。
在这里插入图片描述

第三个模板参数其实和operator*()一样,普通迭代器返回T&,const迭代器返回 const T&
第三个operator->()普通迭代器返回返回的是T* , const迭代器返回 const T* ,所以又加上一个模板参数Ptr
在这里插入图片描述
在这里插入图片描述

库中对拷贝构造和赋值写的是类名

对拷贝构造和赋值做了特殊处理,但不推荐这么做!我们还是写成类型
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值