list的模拟实现
小杨
list相关类要实现的接口
namespace yang
{
// List的节点类
template<class T>
struct ListNode
{
ListNode(const T& val = T());
ListNode<T>* _prev;
ListNode<T>* _next;
T _val;
};
//List的迭代器类
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
public:
typedef Ref Ref;
typedef Ptr Ptr;
public:
// 构造
ListIterator(Node* node = nullptr);
// 具有指针类似行为
Ref operator*();
Ptr operator->();
// 迭代器支持移动
Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
// 迭代器支持比较
bool operator!=(const Self& l)const;
bool operator==(const Self& l)const;
Node* _node;
};
//List的反向迭代器类
template<class Iterator>
class ReverseListIterator
{
// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量
// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:
typedef typename Iterator::Ref Ref;
typedef typename Iterator::Ptr Ptr;
typedef ReverseListIterator<Iterator> Self;
public:
// 构造
ReverseListIterator(Iterator it);
// 具有指针类似行为
Ref operator*();
Ptr operator->();
// 迭代器支持移动
Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
// 迭代器支持比较
bool operator!=(const Self& l)const;
bool operator==(const Self& l)const;
Iterator _it;
};
//List类
template<class T>
class list
{
typedef ListNode<T> Node;
public:
// 正向迭代器
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
// 反向迭代器
typedef ReverseListIterator<iterator> reverse_iterator;
typedef ReverseListIterator<const_iterator> const_reverse_iterator;
public:
// List的构造
list();
list(int n, const T& value = T());
template <class Iterator>
list(Iterator first, Iterator last);
list(const list<T>& l);
list<T>& operator=(list<T> l);
~list();
// List的迭代器
iterator begin();
iterator end();
const_iterator begin()const;
const_iterator end()const;
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin()const;
const_reverse_iterator rend()const;
// List的容量相关
size_t size()const;
bool empty()const;
void resize(size_t newsize, const T& data = T());
// List的元素访问操作
// 注意:List不支持operator[]
T& front();
const T& front()const;
T& back();
const T& back()const;
// List的插入和删除
void push_back(const T& val);
void pop_back();
void push_front(const T& val);
void pop_front();
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val;
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos);
void clear();
void swap(bite::list<T>& l);
private:
void CreateHead();
private:
Node* _head;
};
}
List的节点类模拟实现
list在容器中是带头双向循环列表
他由一个一个的节点所构成,而这每一个节点,又由
**(前驱指针_prev、后继指针_next、当前节点值_val)**所构成。
那么因为list由一个一个节点构成,顾名思义,我们调用list的节点类,即能获得一个节点,因为该节点是我们的自定义类型,因此需要我们自己来进行写其的构造函数.
我们初始的节点,前驱节点和后继结点都置为空即可,节点所要存储的值传给_val即可。
template<class T>
struct ListNode
{
ListNode(const T& val = T());
ListNode<T>* _prev;
ListNode<T>* _next;
T _val;
};
//注意:这里参数给的是缺省参数,const T& val=T(),即给的缺省参数还是匿名对象,这个的好处就是,如果你存的是自定义类型的对象,那么就会调用自定义类型的默认构造,重点在后面,在C++中,可以认为int等内置类型也有构造。比如说 int k =int();
List的正向和反向迭代器
首先说明,迭代器的实现方式一共有两种
种类 | 举例 |
---|---|
原生态指针 | vector |
原生态指针封装 | list |
对于原生态指针来说,他们的底层往往是连续的,能通过指针增减以及解引用操作,就可以对所存储位置的数据进行一系列操作,因此vector当中的迭代器就是原生指针。
但是对于list来说,其各个节点在内存中的位置不确定,并不一定是连续的,因此必须借助迭代器封装 ,对其相应节点运算符进行重载,使得我们可以不用关心他们的底层,就可以实现像原生态指针类似的操作(对所存储位置进行一系列的操作)。例如,当你使用list当中的迭代器进行自增操作时,实际上执行了p = p->next语句,只是你不知道。
我们先看一下正向和反向迭代器的模版参数
迭代器类型 | 迭代器模版参数 |
---|---|
正向迭代器 | template<class T, class Ref, class Ptr> |
反向迭代器 | template |
是不是会有些许疑惑,这都是神魔奇怪名字?
让我们把目光放到全局,看到List类的模拟实现中
上图中可以看到,list的模拟实现中,typedef了4个迭代器类型,普通正向迭代器、const正向迭代器、普通反向迭代器、const反向迭代器.
目前了解到的:
我们发现,在正向迭代器类中Ref是引用类型,Ptr是指针类型。然后我们将正向迭代器typedef成了 iterator,将const正向迭代器typedef了const_iterator.而反向迭代器中的模版参数Iterator呢?
会发现,就是我们所想的那样,Iteartor就是刚才正向迭代器typedef后的iterator,也就是说反向迭代器的模版参数用的是正向迭代器,这么做的目的是是反向迭代器可以用正向迭代器的元素。
因为在正向迭代器中有以下代码
// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
public:
typedef Ref Ref;
typedef Ptr Ptr;
这就意味反向迭代器可以用到正向迭代器中的Ref(引用)和Ptr指针。从而复用了代码。
同理,const反向迭代器和cosnt正向迭代器的关系也是如此。只不过多了const修饰,仅此而已。
总结:反向迭代器类依赖于正向迭代器类。反向迭代器类的实现通常会使用正向迭代器类作为其内部成员,通过正向迭代器类的操作来实现反向遍历。尽管反向迭代器依赖于正向迭代器,但它们是独立的类。反向迭代器类封装了正向迭代器类的实例,并通过重载操作符来提供反向遍历的功能。
构造函数
迭代器类实际上就是对节点指针进行了封装,因此其成员变量就只有一个即节点指针。
在方向迭代器类中,实例化了一个正向迭代器,其目的是用来反向迭代器类的实现。
并且反向迭代器的构造函数,应该是要接受一个正向迭代器作为参数,并赋值给成员变量,即我们刚才实例化的那个正向迭代器对象。并且传递这个正向迭代器参数,我们的反向迭代器就可以知道从哪个位置开始进行反向遍历。总的来说:这体现了封装的好处,就是我们通过封装一个正向迭代器实力,然后根据此我们可以利用正向迭代器的功能来实现反向遍历,即反向迭代器类不需要重新实现正向迭代器类的所有功能。
//正向迭代器构造
ListIterator(Node* node = nullptr)
:_node(node);
{
}
// 反向迭代器构造
ReverseListIterator(Iterator it)
:_it(it)
{
}
++运算符的重载
前置++
正向迭代器:将数据自增,然后返回自增后的数据。
反向迭代器:将数据自减,然后返回自减后的数据。
//正向迭代器
Self& operator++()
{
_node = _node->_next;
return *this;
}
//反向迭代器
Self& operator++()
{
--_it;
return *this;
}
后置++
正向迭代器:先保存当前节点指针的指向,然后让指针指向下一个,然后返回刚才保存的那个。
反向迭代器:先保存当前节点指针的指向,然后让指针指向前一个,然后返回刚才保存的那个。
//正向迭代器
Self operator++(int)
{
Self temp(*this);
_node = _node->_next;
return temp;
}
//反向迭代器
Self operator++(int)
{
Self temp(*this);
--_it;
return temp;
}
- -运算符的重载
前置--
正向迭代器:让节点先向前走一步,然后返回减减后的节点指针
反向迭代器:让节点先向后走一步,然后返回加加后的节点指针
//正向迭代器
Self& operator--()
{
_node = _node->_prev;
return *this;
}
//反向迭代器
Self& operator--()
{
++_it;
return *this;
}
后置--
正向迭代器:先保存当前节点,然后指向前一个节点,最后返回保存的节点
反向迭代器:先保存当前节点,然后指向后一个节点,最后返回保存的节点
//正向迭代器
Self operator--(int)
{
Self temp(*this);
_node = _node->_prev;
return *this;
}
//反向迭代器
Self operator--(int)
{
Self temp(*this);
++_it;
return temp;
}
==运算符重载和!=运算符重载
判断这两个迭代器是否是同一个位置的迭代器。
//正向迭代器
bool operator!=(const Self& l)const
{
return _node != l._node;
}
bool operator==(const Self& l)const
{
return _node == l._node;
}
//反向迭代器
bool operator!=(const Self& l)const
{
return _it != l._it;
}
bool operator==(const Self& l)const
{
return _it == l._it;
}
*运算符重载
正向迭代器:返回当前节点的数据
反向迭代器:保存当前节点并拷贝一份副本,然后--副本,最后返回。原因:反向迭代器指向的位置实际上是正向迭代器的前一个位置。也就是说,如果正向迭代器_it指向位置i,那么反向迭代器应该返回位置i-1的元素。
//正向迭代器
Ref operator*()
{
return _node->_val;
}
//反向迭代器
Ref operator*()
{
Iterator temp(_it);
--temp;
return *temp;
}
->运算符的重载
正向迭代器:直接返回节点当中所存储数据的地址即可。
反向迭代器:复用operator*()并且取地址就可以。
//正向迭代器
Ptr operator->()
{
return &_node->_val;
}
//反向迭代器
Ptr operator->()
{
return &(operator*());
}
list的模拟实现
Member functions(成员函数)
默认构造函数
申请一个头节点,然后让前驱和后继指针都指向自己。
list()
{
CreateHead();
}
private:
void CreateHead()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
n个元素构造
创建头结点,然后遍历n次,逐个插入。
list(int n, const T& value = T())
{
CreateHead();//创建头节点
for (int i = 0; i < n; ++i)
{
push_back(value);//依次尾插
}
}
迭代器区间构造
因为可能要构造的类型不同,因此诞生了迭代器区间构造,构造一个包含与[first,last]范围相同数量元素的容器。
cpp
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
拷贝构造函数
先申请一个头节点,并让前驱指针和后继指针都指向自己,然后将所给容器中的数据,通过遍历的方式一个个尾插到新构造的容器后面.
这里也可以调用迭代器区间构造一个临时对象temp,然后与其进行交换。
list(const list<T>& l)
{
CreateHead();
//list<T> temp(l.begin(), l.end());
//swap(temp);
for (const auto& e : l)
{
push_back(e); //将容器lt当中的数据一个个尾插到新构造的容器后面
}
}
赋值拷贝构造
不穿引用,通过编译器自动调用list的拷贝构造函数构造一个临时对象,然后调用swap交换。
cpp
list<T>& operator=(list<T> l)
{
swap(l);
return *this;
}
析构函数
先调用clear函数清理容器当中的数据,然后将头结点释放,并且置空。
~list()
{
clear();
delete _head;
_head = nullptr;
}
迭代器相关函数
begin(const begin)函数返回的是第一个有效数据的迭代器,end函数返回的是最后一个有效数据的下一个位置的迭代器。
在当前情况下,最开始创建的头节点就是最后一个有效数据的下一个位置,即end,而刚开始创建头结点的下一个元素就是第一个有效元素
// List的迭代器
//正向迭代器begin
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
//const正向迭代器begin
const_iterator begin()const
{
return const_iterator(_head->_next);
}
//const正向迭代器end
const_iterator end()const
{
return const_iterator(_head);
}
//反向迭代器rbegin
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
//反向迭代器rend
reverse_iterator rend()
{
return reverse_iterator(begin());
}
//const 反向迭代器rbegin
const_reverse_iterator rbegin()const
{
return const_reverse_iterator(end());
}
//const 反向迭代器rend
const_reverse_iterator rend()const
{
return const_reverse_iterator(begin());
}
capacity(容量相关)
size
从第一个有效数据开始,定义一个变量count来计数,到最后一个有效数据的下一个位置为止。
size_t size()const
{
Node* cur = _head->_next;
size_t count = 0;
while (cur != _head)
{
count++;
cur = cur->_next;
}
return count;
}
empty
看当前节点的下一个节点是否是自己,如果是自己,那么就没有有效元素。
bool empty()const
{
return _head->_next == _head;
}
resize
先看当前有效数据个数,如果当前数据有效个数大于resize所传递的参数,那么就要减少有效数据的个数,
否则,当前有效数据个数小于resize所传递的参数时,尾插。
void resize(size_t newsize, const T& data = T())
{
size_t oldsize = size();
//如果newsize比oldsize小,那么就要缩小有效数据个数
if (newsize < oldsize)
{
pop_back();
--oldsize;
}
else
{
while (oldsize < newsize)
{
push_back(data);
++oldsize;
}
}
}
list的元素访问操作
List不支持operator[ ]
front返回第一个有效数据的值
back返回最后一个有效数据的值
front或者back加上const意思不变,唯一不同的就是权限从可读可写变成了只读。
T& front()
{
return _head->_next->_val;
}
const T& front()const
{
return _head->_next->_val;
}
T& back()
{
return _head->_prev->_val;
}
const T& back()const
{
return _head->_prev->_val;
}
list的插入和删除
insert
在pos位置前插入值为val的节点
新建一个节点,然后保存插入前的pos位置的节点,然后先将新节点插入,然后相邻节点连接新节点。
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
Node* newnode = new Node(val);
//当前pos位置的节点
Node* cur = pos._node;
//先将新节点插入
newnode->_prev=cur->_prev;
newnode->_next = cur;
newnode->_prev->_next = newnode;
cur->_prev = newnode;
return iterator(newnode);
}
erase
记录当前要删除的节点,然后记录一下当前节点的前一个位置。然后移除要删除的节点。最后释放掉要删除的节点。
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
Node* del = pos._node;
Node* rdel = pos._node->_prev;
del->_prev->_next = del->_next;
del->_next->_prev = rdel;
delete del;
return iterator(rdel->_next);
}
push_back和pop_back
复用insert和erase
push_back函数就是在头结点前插入结点,而pop_back就是删除头结点的前一个结点。
void push_back(const T& val)
{
insert(end(), val);
}
void pop_back()
{
erase(--end());
}
push_front和pop_front
复用insert和erase
push_front函数就是在第一个有效节点前插入结点,而pop_front就是删除第一个有效节点。
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
clear
删除有效数据。在准备删除有效数据前时,要先将这个有效数据的后一个和头结点的next相连接,然后再删除有效数据的节点,然后继续向下进行。
void clear()
{
Node* cur = _head->_next;
// 采用头删除删除
while (cur != _head)
{
_head->_next = cur->_next;
delete cur;
cur = _head->_next;
}
_head->_next = _head->_prev = _head;
}
swap
调用库函数中的
swap函数用于交换两个容器,list容器当中存储的实际上就只有链表的头指针,我们将这两个容器当中的头指针交换即可。
void swap(bite::list<T>& l)
{
std::swap(_head, l._head);
}
list模拟实现总代码
#pragma once
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
namespace yang
{
// List的节点类
template<class T>
struct ListNode
{
ListNode(const T& val = T())
:_prev(nullptr)
,_next(nullptr)
,_val(val)
{}
ListNode<T>* _prev;
ListNode<T>* _next;
T _val;
};
/*
List 的迭代器
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
1. 原生态指针,比如:vector
2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1. 指针可以解引用,迭代器的类中必须重载operator*()
2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前移动,所以需要重载,如果是forward_list就不需要重载--
4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
*/
template<class T, class Ref, class Ptr>
class ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
public:
typedef Ref Ref;
typedef Ptr Ptr;
public:
// 构造
ListIterator(Node* node = nullptr)
:_node(node)
{
}
// 具有指针类似行为
Ref operator*()
{
return _node->_val;
}
Ptr operator->()
{
return &_node->_val;
}
// 迭代器支持移动
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self temp(*this);
_node = _node->_next;
return temp;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self temp(*this);
_node = _node->_prev;
return *this;
}
// 迭代器支持比较
bool operator!=(const Self& l)const
{
return _node != l._node;
}
bool operator==(const Self& l)const
{
return _node == l._node;
}
Node* _node;
};
template<class Iterator>
class ReverseListIterator
{
// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量
// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:
typedef typename Iterator::Ref Ref;
typedef typename Iterator::Ptr Ptr;
typedef ReverseListIterator<Iterator> Self;
public:
// 构造
ReverseListIterator(Iterator it)
:_it(it)
{
}
// 具有指针类似行为
Ref operator*()
{
Iterator temp(_it);
--temp;
return *temp;
}
Ptr operator->()
{
return &(operator*());
}
// 迭代器支持移动
Self& operator++()
{
--_it;
return *this;
}
Self operator++(int)
{
Self temp(*this);
--_it;
return temp;
}
Self& operator--()
{
++_it;
return *this;
}
Self operator--(int)
{
Self temp(*this);
++_it;
return temp;
}
// 迭代器支持比较
bool operator!=(const Self& l)const
{
return _it != l._it;
}
bool operator==(const Self& l)const
{
return _it == l._it;
}
Iterator _it;
};
template<class T>
class list
{
typedef ListNode<T> Node;
public:
// 正向迭代器
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
// 反向迭代器
typedef ReverseListIterator<iterator> reverse_iterator;
typedef ReverseListIterator<const_iterator> const_reverse_iterator;
public:
// List的构造
list()
{
CreateHead();
}
list(int n, const T& value = T())
{
CreateHead();//创建头节点
for (int i = 0; i < n; ++i)
{
push_back(value);//依次尾插
}
}
template <class Iterator>
list(Iterator first, Iterator last)
{
CreateHead();
while (first != last)
{
push_back(*first);
++first;
}
}
list(const list<T>& l)
{
CreateHead();
//list<T> temp(l.begin(), l.end());
//swap(temp);
for (const auto& e : l)
{
push_back(e); //将容器lt当中的数据一个个尾插到新构造的容器后面
}
}
list<T>& operator=(list<T> l)
{
swap(l);
return *this;
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
// List的迭代器
// List的迭代器
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin()const
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator rbegin()const
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend()const
{
return const_reverse_iterator(begin());
}
// List的容量相关
size_t size()const
{
Node* cur = _head->_next;
size_t count = 0;
while (cur != _head)
{
++count;
cur = cur->_next;
}
return count;
}
bool empty()const
{
return _head->_next == _head;
}
void resize(size_t newsize, const T& data = T())
{
size_t oldsize = size();
//如果newsize比oldsize小,那么就要缩小有效数据个数
if (newsize < oldsize)
{
pop_back();
--oldsize;
}
else
{
while (oldsize < newsize)
{
push_back(data);
++oldsize;
}
}
}
// List的元素访问操作
// 注意:List不支持operator[]
T& front()
{
return _head->_next->_val;
}
const T& front()const
{
return _head->_next->_val;
}
T& back()
{
return _head->_prev->_val;
}
const T& back()const
{
return _head->_prev->_val;
}
// List的插入和删除
void push_back(const T& val)
{
insert(end(), val);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_front()
{
erase(begin());
}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
Node* newnode = new Node(val);
//当前pos位置的节点
Node* cur = pos._node;
//先将新节点插入
newnode->_prev=cur->_prev;
newnode->_next = cur;
newnode->_prev->_next = newnode;
cur->_prev = newnode;
return iterator(newnode);
}
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
Node* del = pos._node;
Node* rdel = pos._node->_prev;
del->_prev->_next = del->_next;
del->_next->_prev = rdel;
delete del;
return iterator(rdel->_next);
}
void clear()
{
Node* cur = _head->_next;
// 采用头删除删除
while (cur != _head)
{
_head->_next = cur->_next;
delete cur;
cur = _head->_next;
}
_head->_next = _head->_prev = _head;
}
void swap(yang::list<T>& l)
{
std::swap(_head, l._head);
}
private:
void CreateHead()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
private:
Node* _head;
};
}
/
//对模拟实现的list进行测试
//正向打印链表
template<class t>
void printlist(const yang::list<t>& l)
{
auto it = l.begin();
while (it != l.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
// 测试list的构造
void testbitelist1()
{
yang::list<int> l1;
yang::list<int> l2(10, 5);
printlist(l2);
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
yang::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));
printlist(l3);
yang::list<int> l4(l3);
printlist(l4);
l1 = l4;
printlist(l1);
}
// pushback()/popback()/pushfront()/popfront()
void testbitelist2()
{
// 测试pushback与popback
yang::list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
printlist(l);
l.pop_back();
l.pop_back();
printlist(l);
l.pop_back();
cout << l.size() << endl;
// 测试pushfront与popfront
l.push_front(1);
l.push_front(2);
l.push_front(3);
printlist(l);
l.pop_front();
l.pop_front();
printlist(l);
l.pop_front();
cout << l.size() << endl;
}
// 测试insert和erase
void testbitelist3()
{
int array[] = { 1, 2, 3, 4, 5 };
yang::list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto pos = l.begin();
l.insert(l.begin(), 0);
printlist(l);
++pos;
l.insert(pos, 2);
printlist(l);
l.erase(l.begin());
l.erase(pos);
printlist(l);
// pos指向的节点已经被删除,pos迭代器失效
cout << *pos << endl;
auto it = l.begin();
while (it != l.end())
{
it = l.erase(it);
}
cout << l.size() << endl;
}
// 测试反向迭代器
void testbitelist4()
{
int array[] = { 1, 2, 3, 4, 5 };
yang::list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto rit = l.rbegin();
while (rit != l.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
const yang::list<int> cl(l);
auto crit = l.rbegin();
while (crit != l.rend())
{
cout << *crit << " ";
++crit;
}
cout << endl;
}