List容器
一、list容器基本概念
- list容器使用链表存储,链表是由一系列节点构成,每个节点都有自己的存储空间。
- list容器中的链表是双向环状链表链表,其尾节点指向头节点
二、链表节点结构体
template<typename T>
struct ListNode
{
ListNode<T>*_prev;
ListNode<T>*_next;
T _data;
};
使用模板,包含一个前指针,一个后指针,和一个数据域
三、迭代器构建
//Ref指T&引用,Ptr指T*指针,采用三个参数是为了便于const迭代器构建,只需在后两个参数前加上const限定即可,不必重写一个
template<typename T, typename Ref, typename Ptr>
class ListIterator
{
public:
ListNode<T>*_node;
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> self;
ListIterator(Node*node)//构造函数
{
this->_node = node;
}
Ref operator*()//解引用
{
return this->_node->_data;
}
Ptr &operator->()//指针访问
{
return &(this->_node->_data);
}
self&operator++()//前置++
{
this->_node = this->_node->_next;
return *this;
}
self&operator++(int)//后置++
{
self temp(*this);
this->_node = this->_node->_next;
return temp;
}
self&operator--()//前置--
{
this->_node = this->_node->_prev;
return *this;
}
self&operator--(int)//后置--
{
self temp(*this);
this->_node = this->_node->_prev;
return temp;
}
bool operator!=(const self&it)
{
return this->_node != it._node;
}
bool operator==(const self&it)
{
return this->_node == it._node;
}
};
这是一个双向迭代器,即可正向访问,也可反向访问,因为重载了++和–
四、list类成员、命名及构造函数
public:
typedef ListNode<T> Node;
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
private:
Node*_head;
void CreatHead()
{
this->_head = new Node;
this->_head->_prev = this->_head->_next = this->_head;
}
私有成员为一个头指针,简化模板迭代器命名,CreatHead在构造函数中多次用到,简化为一个函数,避免重复代码
以下函数均在类外实现
template<typename T>
mlist<T>::mlist()//无参构造
{
this->CreatHead();
}
template<typename T>
mlist<T>::mlist(iterator begin, iterator end)//迭代器构造
{
this->CreatHead();
while (begin != end)
{
this->push_back(*begin);//采用类内函数调用实现,减少代码量
++begin;
}
}
template<typename T>
mlist<T>::mlist(size_t n, const T & elmn)//传入n个elmn
{
this->CreatHead();
for (size_t i = 0; i < n; i++)
this->push_back(elmn);
}
template<typename T>
mlist<T>::mlist(mlist<T> & list)//拷贝构造
{
this->CreatHead();
this->assign(list.begin(), list.end());
}
五、assign()函数
赋值函数
template<typename T>
void mlist<T>::assign(iterator begin, iterator end)
{
this->CreatHead();
this->insert(this->begin(), begin, end);
}
template<typename T>
void mlist<T>::assign(size_t n, const T & elmn)
{
this->CreatHead();
for (size_t i = 0; i < n; i++)
this->push_back(elmn);
}
迭代器的赋值函数还可以有const的版本,这里就不在多写,过于麻烦,这样,insert函数也要写const版本,很多函数都要在写个const版本,这就是个只读限定,防止数据被修改
六、重载=号运算符
template<typename T>
mlist<T> & mlist<T>::operator=(mlist<T> & list)
{
this->CreatHead();
this->assign(list.begin(),list.end());
return*this;
}
用assign赋值,返回本身
七、swap()交换函数
template<typename T>
void mlist<T>::swap(mlist<T> & list)
{
std::swap(this->_head, list._head);
}
调用std的swap交换对象中的头节点即可实现交换
八、size()函数和empty()函数
template<typename T>
size_t mlist<T>::size()
{
size_t count = 0;
for (mlist<T>::iterator it = this->begin(); it != this->end(); it++)
count++;
return count;
}
template<typename T>
bool mlist<T>::empty()
{
return this->begin() == this->end();
}
遍历链表计数
头尾相等为空
九、resize()函数
指定链表长度
template<typename T>
void mlist<T>::resize(size_t n, const T & elmn)
{
size_t len = this->size();
if (n <= len)//缩小删除
{
for (size_t i = n; i < len; i++)
this->pop_back();
}
else
this->insert(this->end(), n - len, elmn);//增大插入元素
}
现在想想不用写两个,用一个默认值(声明与定义只能标明一处,这里默认为0)实现,避免函数重载
十、头尾的删除、增添、取值
template<typename T>
void mlist<T>::push_back(const T & elmn)
{
insert(this->end(), elmn);
}
template<typename T>
void mlist<T>::pop_back()
{
this->erase(--this->end());
}
template<typename T>
void mlist<T>::push_front(const T & elmn)
{
this->insert(this->begin(), elmn);
}
template<typename T>
void mlist<T>::pop_front(