- list的概念及使用
概念:list的底层数据结构是带头双向循环链表,是可以在任意位置进行插入和删除的序列式容器,并且该容器可以进行前后迭代。
使用:
1、构造:
list():构造无参的list
list(size_t n,const value_type& val=value_type()):n个值为val的元素构造list
list(const list& x):拷贝构造函数
list(iterator first,iterator last):在(first,last)区间构造
2、使用:
begin+end:返回第一个元素的迭代器+最后一个元素的下一个位置的迭代器
rbegin+rend:返回最后一个元素的反向迭代器+第一个元素前一个位置的反向迭代器
3、容量操作:
empty:判空
size:获取元素个数
4、list access
front+back:获取第一个元素和最后一个元素
5、list的修改
push_front+push_back:头插和尾插
pop_front+pop_back:头删和尾删
insert+erase:任意位置插入和任意位置删除
clear:清空list中的有效元素
swap:交换两个list中的元素 - list的迭代器失效
迭代器的本质就是指针,可以帮助用户透明化地遍历容器,用户可以不用知道容器底层的数据结构。
迭代器失效指:迭代器类似于指针,list的迭代器失效即迭代器指向的结点失效,即该节点被删除了 - list的模拟实现
1、list的模拟实现,首先要实现它的迭代器,迭代器有两种实现方式,例如在vector中使用的是原生态指针,而在list中,不能使用原生态指针,必须要对原生态指针进行封装,因为没有办法++让迭代器向后移动到下一个下一个节点。
2、给一个容器实现迭代器:
(1)根据该数据结构的特性,实现一个迭代器类,即对原生态指针进行封装,封装中必须实现:
1> 构造、拷贝构造
2> 指针可以解引用,迭代器类中必须重载operator*()
3> 指针可以通过->来访问所指空间内容,迭代器类中必须重载operator->()
4> 指针可以++向后移动,必须重载operator++()和operator++(int)(分为前置++和后置++),而operator–()和operator–(int)是否需要重载,根据具体的数据结构来抉择,例如forward_list是单链表,就不需要–,就不用重载
5> 迭代器需要进行是否相等的比较,要重载operator==()和operator!=()
(2)在容器类中给迭代器起别名(为了类型统一) typedef 迭代器类型 iterator
(3)在容器类中实现begin()和end();
例如模拟实现list:
struct ListNode//生成代码的一个工具
{
ListNode(const T& data = T())//构造结点
:_pNext(nullptr)
, _pPre(nullptr)
, _data(data)
{}
ListNode<T>* _pNext;
ListNode<T>* _pPre;
T _data;
};
首先ListNode不是一个真正的类,而是编译器生成具体存放数据类型的模具,起一个封装的作用
然后实现list迭代器类:
namespace Daisy
{
template<class T>
struct list_iterator//重新给出迭代器,封装
{
typedef T ValueType;
typedef ListNode<T> Node;
typedef Node* pNode;
typedef list_iterator<T> Self;
li