list模拟实现
- 1 模块分析
- 1.1 list的结构
- 1.2 ListNode的结构
- 1.3 迭代器类
- 2 ListNode节点设计
- 3 迭代器类设计
- 3.1 迭代器类框架
- 3.2 模板设计
- 3.3 operator++()前置++和后置++
- 3.4 operator--()前置--和后置--
- 3.4 operator*()
- 3.5 operator->()
- 3.6 operator!=() 和 operator==()
- 3.7 迭代器类全部代码
- 4 list类实现
- 4.1 list 类框架
- 4.2 构造函数
- 4.2.1 无参构造list()
- 4.2.2 迭代器构造 list(iterator first, iterator last)
- 4.2.3 拷贝构造
- 4.2.4 n个值的构造 list(size_t n, const T& x)
- 4.3 赋值运算符重载
- 4.4 析构函数 ~list()
- 4.5迭代器相关函数
- 4.6访问容器相关函数
- 4.7 容量相关函数
- 4.7.1 size()
- 4.7.2 empty()
- 4.7.3 resize(size_t n, const T& x = T())
- 4.8 增删查改相关的函数
- 4.8.1 Insert(iterator pos, const T& x)
- 4.8.2 Erase(iterator pos)
- 5.8.3 push_back 和 push_front
- 5.8.4 pop_back 和 pop_front
- 6总结
- 6.1 list.h
- 6.2 list.cpp
- 6.3 test_list.cpp
1 模块分析
1.1 list的结构
list
是一个带头双向循环链表的结构,每一个节点是ListNode
。
ListNode
的结构是有两个指针,分别是_prev
和_next
,还有一个存储节点值的_data
1.2 ListNode的结构
ListNode的成员有三个,分别是:
1. 存储前一个结点的 _prev
2. 存储 后一个结点的_next
3. 存储 值的_data
1.3 迭代器类
1. 为什么要添加一个迭代器类?为什么vector不需要添加?
首先回答为什么vector不需要添加,因为 vector的空间是连续的。当vector访问下一个元素的时候,直接++就能找到下一个元素。 而list的空间是不连续的,所以++是找不到下一个元素的,必须使用
node = node->next
这样的方式找到下一个元素的位置。
为什么要添加迭代器类?其实是可以不添加的,在list遍历的时候,直接使用
node = node->next
也可以,但是 为了STL的容器的操作方式统一,就有必要添加一个迭代器类来封装一下接口。让list也能使用++来实现访问下一个元素。
2 ListNode节点设计
template <class T>
struct ListNode
{
ListNode<T>* _prev;
ListNode<T>* _next;
T _data;
//构造函数
ListNode(const T& x = T())
:_prev(nullptr)
,_next(nullptr)
,_data(x)
{}
};
3 迭代器类设计
3.1 迭代器类框架
先了解迭代器类的框架,后续会做详细解释。
template <class T, class Ref, class Ptr>
class __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
__list_iterator(Node* node = nullptr)
:_node(node)
{}
public:
//前置++ --> 返回++之后的内容
self& operator++()
{}
//后置++ --> 返回++之前的内容
self operator++(int)
{}
self& operator--()
{}
self operator--(int)
{}
Ref operator*()
{}
Ptr operator->()
{}
bool operator!=(const self& s) const
{}
bool operator==(const self& s) const
{}
private:
Node* _node;
};
3.2 模板设计
template <class T, class Ref, class Ptr>
对迭代器的模板设置了三个模板参数。
2. 为什么要设置三个模板参数?
在下面list中要定义迭代器类型,分别是普通迭代器iterator
和const迭代器const_iterator
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<const T, const T&, const T*> const_iterator;
迭代器类的模板参数列表当中的
Ref
和Ptr
分别代表的是 引用类型(T&) 和 指针类型(T *)。
当我们使用 普通迭代器时,编译器就会实例化出一个 普通迭代器对象;当我们使用 const迭代器时,编译器就会实例化出一个 const迭代器对象。
若该迭代器类不设计三个模板参数,那么就不能很好的区分 – 普通迭代器和 – const迭代器。
因为加上模板之后,名称就太长了,所以我们可以使用typedef
来解决这个问题。
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
3.3 operator++()前置++和后置++
3. 前置++和后置++有什么区别?
前置++返回 ++之后的值。
后置++返回 ++之前的值。
无论是前置++还是后置++,返回的都是迭代器本身。在代码中,应该返回的是 __list_iterator<T, Ref, Ptr>
,但是我们typedef
过了,所以返回的应该是self
。
4. 代码中如何区分前置++和后置++?
//前置++
self& operator++()
//后置++
self operator++ (int)
区分就是 后置++在()中添加一个int作为占位符。
5. 为什么前置++返回self&
而后置++返回self
?
因为前置++返回的是++之后的值,就可以返回this,而this是一直存在的,不会出栈帧之后销毁,函数结束后依然存在。返回引用不会出现问题。返回引用可以减少拷贝次数。
后置++返回的是++之前的值,返回的是一个++之前的 局部变量,出了栈帧会销毁。如果返回引用就会出现问题。只能使用值拷贝。
结合前面几个问题,前置++和后置++的代码如下:
//前置++ --> 返回++之后的内容
self& operator++()
{
_node = _node->_next;
return *this; //this表示self*类型,所以要对this解引用
}
//后置++ --> 返回++之前的内容
self operator++(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
3.4 operator–()前置–和后置–
operator–()和operator++()类似。唯一的不同是_node = _node->_prev;
代码如下:
self& operator--()
{
_node = _node->_prev;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
3.4 operator*()
解引用就是直接获取该位置的数据值。
但是我们可能会对该位置的数据值进行修改,因此需要返回的是引用。因此返回Ref
Ref对应的就是T&
Ref operator*()
{
return _node->_data;
}
3.5 operator->()
->返回的是指针。.因此需要返回Ptr
。
ptr对应的就是T*
Ptr operator->()
{
return &_node->_data;
}
3.6 operator!=() 和 operator==()
bool operator!=(const self& s) const
{
return _node != s._node;
}
bool operator==(const self& s) const
{
return _node == s._node;
}
6. 为什么传入的参数是const self& s
?
首先,这是比较的函数,所以应该传递是相同的类型。调用operator==()的就是self类型,因此传递的也必须是self类型.
其次, 为了减少拷贝,可以传递引用。但是如果只是传递self&,那么const类型的参数无法传递过来。 因为const类型转化为非const类型,属于权限的放大,这是不允许的。因此需要加上const,这样非const类型和const类型都可以传递。
3.7 迭代器类全部代码
template <class T, class Ref, class Ptr>
class __list_iterator
{
public:
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
__list_iterator(Node* node = nullptr)
:_node(node)
{}
public:
//前置++ --> 返回++之后的内容
self& operator++()
{
_node = _node->_next;
return *this; //this表示self*类型,所以要对this解引用
}
//后置++ --> 返回++之前的内容
self operator++(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
self& operator--()
{
_node = _node->_prev;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const self& s) const
{
return _node != s._node;
}
bool operator==(const self& s) const
{
return _node == s._node;
}
Node* _node;
};
4 list类实现
4.1 list 类框架
template <class T>
class list
{
public:
typedef ListNode<T> Node;
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<const T, const T&, const T*> const_iterator;
public:
//迭代器
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
//构造函数
list();
list(size_t n, const T& x = T());
list(iterator first, iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
~list();
//拷贝构造
list(list<T>& lt);
//初始化一个循环链表
void empty_init();
//赋值构造
list<T>& operator=(list<T>& lt);
//容量相关的函数
size_t size();
bool Empty();
void clear();
void resize(size_t n, const T& x = T());
//访问容器相关的函数
T& front();
T& back();
const T& front() const;
const T& back() const;
//修改相关的函数
void push_back(const T& x);
void pop_back();
void push_front(const T& x);
void pop_front();
iterator Insert(iterator pos, const T& x);
iterator Erase(iterator pos);
void swap(list<T>& tmp);
private:
Node* _head;
};
};
4.2 构造函数
4.2.1 无参构造list()
头结点的结构如下:
因此,构造函数就是new一个结点,然后_prev指向头结点,_next指向头结点
template<class T>
zyy::list<T>::list()
{
_head = new Node;
_head->_prev = _head; //指向自己
_head->_next = _head; //指向自己
}
因为后续一直要用到这个创建头结点的操作,因此可以单独增加一个函数来完成这个操作。
template <class T>
void zyy::list<T>::empty_init()
{
_head = new Node;
_head->_prev = _head; //指向自己
_head->_next = _head; //指向自己
}
4.2.2 迭代器构造 list(iterator first, iterator last)
迭代器构造传入两个迭代器,然后将内容从first一直push_back,直到last结束。
list(iterator first, iterator last)
{
empty_init();//创建一个头结点
while (first != last)
{
push_back(*first);
++first;
}
}
4.2.3 拷贝构造
拷贝构造函数的步骤:
1.构造一个头结点lt2
2.调用迭代器构造构造出tmp,tmp和lt1完全相同
3.交换lt2和tmp的头结点
4.tmp最后会自动调用析构函数销毁
template <class T>
zyy::list<T>::list(list<T>& lt)
{
//1.构造一个头结点
empty_init();
//2.迭代器构造一个tmp,内容和lt相同
list<T> tmp(lt.begin(), lt.end());
//3.交换tmp的头结点和头结点
std::swap(tmp._head, _head);
}
4.2.4 n个值的构造 list(size_t n, const T& x)
template<class T>
zyy::list<T>::list(size_t n, const T& x)
{
//1.创造一个头结点
empty_init();
//2.将n个x尾插进来
for (int i = 0; i < n; ++i)
{
push_back(x);
}
}
4.3 赋值运算符重载
步骤:
1.将原来的内容清空
2.将传递进来的list的内容都push_back到原来的结点中
3.返回*this
template<class T>
zyy::list<T>& zyy::list<T>::operator=(list<T>& lt)
{
//将原来的内容清空
clear();
if (this != <) //避免自己复制自己
{
for (auto e : lt)
{
push_back(e);
}
}
return *this;
}
7. 为什么要传引用 ?
传递引用可以不用拷贝,减少开销
8. 返回值类型为什么是list<T>&
?
1.实现连续赋值:
允许连续赋值操作,例如a = b = c
。如果返回值不是引用,那么a = b
会返回一个临时对象,再用这个临时对象去赋值给c会导致一个新的临时对象的创建和赋值,效率较低且不符合通常的连续赋值语义。而返回引用可以直接返回当前对象本身,使得连续赋值能够正确地进行。
2.避免不必要的拷贝:
返回引用避免了返回值的拷贝构造,提高了效率。如果返回值不是引用而是一个值类型,那么每次赋值操作都可能涉及到对象的拷贝构造,对于大型复杂对象来说,这可能是非常昂贵的操作。
除了上面这种实现方式,还有另外一种更高效的实现方式。
将赋值运算符重载的参数定义为list 类型的对象 而不是对象的引用,传参时会发生值拷贝。
因此我们可以把 list对象 的 this指针 和 拷贝出来的参数 L 指向头结点的指针交换,这样 this指针 就直接指向了拷贝出来的L的头结点。L则指向了list对象的头结点,在函数结束后,作为局部对象的L将被销毁,它指向的空间也会被释放。
template<class T>
void zyy::list<T>::swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
template<class T>
zyy::list<T>& zyy::list<T>::operator=(list<T> lt)
{
swap(lt);
return *this;
}
4.4 析构函数 ~list()
先将内容清空,再delete 掉头结点,最后将头结点释放
清空函数:
template<class T>
void zyy::list<T>::clear()
{
auto it = begin();
while (it != end())
{
it = Erase(it);
}
}
析构函数:
template<class T>
zyy::list<T>::~list()
{
//1.清空
clear();
//2.delete掉头结点
delete _head;
//3.置空
_head = nullptr;
}
4.5迭代器相关函数
下面是list中迭代器的位置示意图:
begin 函数返回的是第一个有效数据的迭代器, end函数返回的是最后一个有效数据的下一个位置的迭代器。
对于 list 这个 带头双向循环链表 来说, 其第一个有效数据的迭代器就是使用头结点后一个结点的地址构造出来的迭代器,而其最后一个有效数据的下一个位置的迭代器就是使用头结点的地址构造出来的迭代器。(最后一个结点的下一个结点就是头结点)
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::begin()
{
return iterator(_head->_next);
}
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::end()
{
return iterator(_head);
}
const类型
template<class T>
typename zyy::list<T>::const_iterator zyy::list<T>::begin() const
{
return const_iterator(_head->_next);
}
template<class T>
typename zyy::list<T>::const_iterator zyy::list<T>::end() const
{
return const_iterator(_head);
}
4.6访问容器相关函数
template<class T>
T& zyy::list<T>::front()
{
return *begin();
}
template<class T>
T& zyy::list<T>::back()
{
return *(--end());
}
const类型
template<class T>
const T& zyy::list<T>::front() const
{
return *begin();
}
template<class T>
const T& zyy::list<T>::back() const
{
return *(--end());
}
4.7 容量相关函数
4.7.1 size()
遍历全部的结点,每遍历一个,n += 1
size_t size()
{
int n = 0;
auto it = begin();
while (it != end())
{
++it;
++n;
}
return n;
}
4.7.2 empty()
当头结点和尾结点相等时,则为空
bool Empty()
{
return begin() == end();
}
4.7.3 resize(size_t n, const T& x = T())
resize()函数扩容的规则:
- 若当前容器的size小于所给n,则尾插结点,直到size等于n为止。
- 若当前容器的size大于所给n,则只保留前n个有效数据。
void resize(size_t n, const T& val = T())
{
iterator i = begin(); //获取第一个有效数据的迭代器
size_t len = 0; //记录当前所遍历的数据个数
while (len < n && i != end())
{
len++;
i++;
}
if (len == n) //说明容器当中的有效数据个数大于或是等于n
{
while (i != end()) //只保留前n个有效数据
{
i = erase(i); //每次删除后接收下一个数据的迭代器
}
}
else //说明容器当中的有效数据个数小于n
{
while (len < n) //尾插数据为val的结点,直到容器当中的有效数据个数为n
{
push_back(val);
len++;
}
}
}
4.8 增删查改相关的函数
4.8.1 Insert(iterator pos, const T& x)
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::Insert(iterator pos, const T& x)
{
assert(pos._node);
//1.找到cur和prev
Node* cur = pos._node;
Node* prev = cur->_prev;
//2.创建一个新的结点newnode
Node* newnode = new Node(x);
//3.建立newnode和prev的双向关系
prev->_next = newnode;
newnode->_prev = prev;
//4.建立newnode和cur的双向关系
cur->_prev = newnode;
newnode->_next = cur;
return iterator(newnode);
}
4.8.2 Erase(iterator pos)
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::Erase(iterator pos)
{
assert(pos._node); //检测pos的合法性
assert(pos != end()); //删除的结点不能是头结点
Node* cur = pos._node; //迭代器pos处的结点指针
Node* prev = cur->_prev; //迭代器pos前一个位置的结点指针
Node* next = cur->_next; //迭代器pos后一个位置的结点指针
delete cur; //释放cur结点
//建立prev与next之间的双向关系
prev->_next = next;
next->_prev = prev;
return iterator(next); //返回所给迭代器pos的下一个迭代器
}
5.8.3 push_back 和 push_front
可以复用Insert()函数
push_back是在头结点前插入一个结点.
void push_back(const T& x)
{
Insert(end(), x);
}
push_front函数就是在第一个有效结点前插入结点
void push_front(const T& x)
{
Insert(begin(), x);
}
5.8.4 pop_back 和 pop_front
可以复用Erase()函数
pop_back就是删除头结点的前一个结点
void pop_back()
{
Erase(--end());
}
pop_front就是删除第一个有效结点。
void pop_front()
{
Erase(begin());
}
6总结
6.1 list.h
#pragma once
#include<iostream>
#include<assert.h>
#include<string>
using std::istream;
using std::ostream;
using std::endl;
using std::cout;
namespace zyy
{
template <class T>
struct ListNode
{
ListNode<T>* _prev;
ListNode<T>* _next;
T _data;
//构造函数
ListNode(const T& x = T())
:_prev(nullptr)
,_next(nullptr)
,_data(x)
{}
};
template <class T, class Ref, class Ptr>
class __list_iterator
{
public:
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> self;
__list_iterator(Node* node = nullptr)
:_node(node)
{}
public:
//前置++ --> 返回++之后的内容
self& operator++()
{
_node = _node->_next;
return *this; //this表示self*类型,所以要对this解引用
}
//后置++ --> 返回++之前的内容
self operator++(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
self& operator--()
{
_node = _node->_prev;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_prev;
return tmp;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const self& s) const
{
return _node != s._node;
}
bool operator==(const self& s) const
{
return _node == s._node;
}
Node* _node;
};
template <class T>
class list
{
public:
typedef ListNode<T> Node;
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<const T, const T&, const T*> const_iterator;
public:
//迭代器
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
//构造函数
list()
{
_head = new Node;
_head->_prev = _head; //指向自己
_head->_next = _head; //指向自己
}
list(size_t n, const T& x = T());
list(iterator first, iterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
~list()
{
//1.清空
clear();
//2.delete掉头结点
delete _head;
//3.置空
_head = nullptr;
}
//拷贝构造
list(list<T>& lt);
//初始化一个循环链表
void empty_init();
//list<T>& operator=(list<T>& lt);
//赋值构造 -- 传递值,而不是引用
list<T>& operator=(list<T> lt);
//容量相关的函数
size_t size()
{
int n = 0;
auto it = begin();
while (it != end())
{
++it;
++n;
}
return n;
}
bool Empty()
{
return begin() == end();
}
void clear()
{
auto it = begin();
while (it != end())
{
it = Erase(it);
}
}
void resize(size_t n, const T& val = T())
{
iterator i = begin(); //获取第一个有效数据的迭代器
size_t len = 0; //记录当前所遍历的数据个数
while (len < n && i != end())
{
len++;
i++;
}
if (len == n) //说明容器当中的有效数据个数大于或是等于n
{
while (i != end()) //只保留前n个有效数据
{
i = Erase(i); //每次删除后接收下一个数据的迭代器
}
}
else //说明容器当中的有效数据个数小于n
{
while (len < n) //尾插数据为val的结点,直到容器当中的有效数据个数为n
{
push_back(val);
len++;
}
}
}
//访问容器相关的函数
T& front();
T& back();
const T& front() const;
const T& back() const;
//修改相关的函数
void push_back(const T& x)
{
Insert(end(), x);
}
void pop_back()
{
Erase(--end());
}
void push_front(const T& x)
{
Insert(begin(), x);
}
void pop_front()
{
Erase(begin());
}
iterator Insert(iterator pos, const T& x);
iterator Erase(iterator pos);
void swap(list<T>& tmp);
void print_list()
{
auto it = begin();
while (it != end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
private:
Node* _head;
};
};
6.2 list.cpp
#include "list.h"
//template<class T>
//zyy::list<T>::list()
//{
// _head = new Node;
// _head->_prev = _head; //指向自己
// _head->_next = _head; //指向自己
//}
template <class T>
void zyy::list<T>::empty_init()
{
_head = new Node;
_head->_prev = _head; //指向自己
_head->_next = _head; //指向自己
}
template <class T>
zyy::list<T>::list(list<T>& lt)
{
//1.构造一个头结点
empty_init();
//2.迭代器构造一个tmp,内容和lt相同
list<T> tmp(lt.begin(), lt.end());
//3.交换tmp的头结点和头结点
std::swap(tmp._head, _head);
}
template<class T>
zyy::list<T>::list(size_t n, const T& x)
{
//1.创造一个头结点
empty_init();
//2.将n个x尾插进来
for (int i = 0; i < n; ++i)
{
push_back(x);
}
}
//template<class T>
//zyy::list<T>& zyy::list<T>::operator=(list<T>& lt)
//{
// //将原来的内容清空
// clear();
// if (this != <) //避免自己复制自己
// {
// for (auto e : lt)
// {
// push_back(e);
// }
// }
//
// return *this;
//}
template<class T>
void zyy::list<T>::swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
template<class T>
zyy::list<T>& zyy::list<T>::operator=(list<T> lt)
{
swap(lt);
return *this;
}
//template<class T>
//void zyy::list<T>::clear()
//{
// auto it = begin();
// while (it != end())
// {
// it = Erase(it);
// }
//}
//template<class T>
//zyy::list<T>::~list()
//{
// //1.清空
// clear();
// //2.delete掉头结点
// delete _head;
// //3.置空
// _head = nullptr;
//}
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::begin()
{
return iterator(_head->_next);
}
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::end()
{
return iterator(_head);
}
template<class T>
typename zyy::list<T>::const_iterator zyy::list<T>::begin() const
{
return const_iterator(_head->_next);
}
template<class T>
typename zyy::list<T>::const_iterator zyy::list<T>::end() const
{
return const_iterator(_head);
}
template<class T>
T& zyy::list<T>::front()
{
return *begin();
}
template<class T>
T& zyy::list<T>::back()
{
return *(--end());
}
template<class T>
const T& zyy::list<T>::front() const
{
return *begin();
}
template<class T>
const T& zyy::list<T>::back() const
{
return *(--end());
}
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::Insert(iterator pos, const T& x)
{
assert(pos._node);
//1.找到cur和prev
Node* cur = pos._node;
Node* prev = cur->_prev;
//2.创建一个新的结点newnode
Node* newnode = new Node(x);
//3.建立newnode和prev的双向关系
prev->_next = newnode;
newnode->_prev = prev;
//4.建立newnode和cur的双向关系
cur->_prev = newnode;
newnode->_next = cur;
return iterator(newnode);
}
template<class T>
typename zyy::list<T>::iterator zyy::list<T>::Erase(iterator pos)
{
assert(pos._node); //检测pos的合法性
assert(pos != end()); //删除的结点不能是头结点
Node* cur = pos._node; //迭代器pos处的结点指针
Node* prev = cur->_prev; //迭代器pos前一个位置的结点指针
Node* next = cur->_next; //迭代器pos后一个位置的结点指针
delete cur; //释放cur结点
//建立prev与next之间的双向关系
prev->_next = next;
next->_prev = prev;
return iterator(next); //返回所给迭代器pos的下一个迭代器
}
6.3 test_list.cpp
#include "list.cpp"
using namespace zyy;
void test1()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
lt.print_list();
}
void test2()
{
list<int> lt;
lt.push_front(1);
lt.push_front(2);
lt.push_front(3);
lt.push_front(4);
lt.push_front(5);
lt.Insert(++lt.begin(), 10);
lt.print_list();
}
void test3()
{
list<int> lt;
lt.push_front(1);
lt.push_front(2);
lt.push_front(3);
lt.push_front(4);
lt.push_front(5);
lt.pop_back();
lt.pop_front();
lt.print_list();
}
void test4()
{
list<int> lt;
lt.push_front(1);
lt.push_front(2);
lt.push_front(3);
lt.push_front(4);
lt.push_front(5);
lt.Erase(++lt.begin());
lt.print_list();
cout << lt.size() << endl;
if (lt.Empty())
{
cout << "lt是空的" << endl;
}
else
{
cout << "lt不是空的" << endl;
}
lt.resize(10, 10);
lt.print_list();
cout << "lt.front(): " << lt.front() << endl;
cout << "lt.back(): " << lt.back() << endl;
}
int main()
{
test4();
return 0;
}