自模拟实现list
公有及私有成员预览
#pragma once
namespace carl
{
template<class T>
struct list_node
{
list_node<T>* _prev;
list_node<T>* _next;
T _data;
//构造结点
list_node(const T& x=T() )
:_prev(nullptr),
_next(nullptr),
_data(x)
{}
};
template<class T>
class list
{
typedef list_node<T> Node;
public:
typedef __list_iterator<T> iterator;
//迭代器相关
iterator begin();
iterator end();
const_iterator begin();const
const_iterator end();const
//默认成员函数
list();
list(const list<T>& lt);
list<T>& operator=(list<T> x);
~list();
//容量相关
size_t size();const
bool empty();
//访问相关
T& front();
T& back();
//修改相关
void push_front(const T& val);
void pop_front();
void push_back(const T& val);
void pop_back();
iterator insert(iterator position, const T& val);
iterator erase(iterator position);
void clear();
private:
Node* _head;
};
}
必读!
知识梳理:(双向带头循环)链表的结构由若干个结点构成,而结点则是由前驱指针,数据元素,后驱指针构成,因此将结点封装为结构体保证其能够被访问(类也行),并且结点需要提供构造函数,配合new(自动调用构造)来完成链表的初始化工作,而链表本身的操控是由一个结点指针头指针完成的,简称哨兵位,通过哨兵位来完成函数接口的实现。链表最重要且有难度的部分在于迭代器,因此我们先讲述迭代器相关部分!
注意:自模拟实现过程其实就是打开大门的过程,使用的时候是什么样的我们就根据样子来将其模拟完成
迭代器
正向迭代器
我们一步一步打开迭代器的大门,迭代器有正向迭代器,const迭代器以及反向迭代器,我们先从正向迭代器出发一步步探索:
前面学习中,迭代器一般是数据类型的指针,而由于vector,string是连续存储的结构,因此++等操作并不需要重载,直接地址+1就能找到下一个位置的迭代器,但链表不同,链表的结构使其不能使用库中的++操作,(因为你根本不知道此结点的地址在哪里,不像vector容器一样只需要知道第一个元素的地址就能知道所有的,链表是非连续存储单元),因此为了使链表的迭代器也能通过++来到下一个结点的迭代器位置,我们需要完成重载操作,(链表的迭代器本质上是一个结构体指针),因此我们需要将迭代器封装成一个类或结构体。
template<class T,class Ref,class Ptr> struct __list_iterator { typedef list_node<T>* link_type; typedef __list_iterator<T,Ref,Ptr> self; //构造 __list_iterator(link_type x) :_node(x) {} __list_iterator(){} __list_iterator(const self& x):_node(x._node){} //迭代器运算符重载 bool operator==(const self& x)const { return _node == x._node; } bool operator!=(const self& x)const { return _node != x._node; } Ref operator*() { return _node->_data; } Ptr operator->() { return &(operator*()); } //前置++ self& operator++() { _node = _node->_next; return *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; } public: link_type _node; };
注意:可以结合源代码来完成,加强读文档技能的同时还能思考大佬们实现时的思路
const迭代器
const迭代器和正向迭代器的区别在于重载 * 和 重载 ->,若我们有一个const类型的迭代器,若不对迭代器做修改直接 进行解引用或-> 操作的话是无法完成的,因为涉及了权限的放大!
但是如何做此修改呢?
思路一:重载
但是传引用和传const引用是无法重载的,因此不可行
思路二:实现两个迭代器类
虽然可行但是破坏了可读性和简洁性
因为只涉及传引用和传const引用,传指针和传const指针问题,那么有没有一种方式能够改变这两个返回值呢?别忘了,C++可是泛型编程!因此,我们可以传模板参数来达到此目的!
template<class T,class Ref,class Ptr> struct __list_iterator { typedef list_node<T>* link_type; typedef __list_iterator<T,Ref,Ptr> self; link_type _node;//迭代器本质为结构体指针 //模板参数 Ref Ref operator*() { return _node->_data; } //模板参数 Ptr Ptr operator->() { return &(operator*()); } }; template<class T> class list { typedef list_node<T> Node; public: //const迭代器就传const模板,非const迭代器就传非const模板 typedef __list_iterator<T,T&,T*> iterator; typedef __list_iterator<T, const T&, const T*> const_iterator;
对于 反向迭代器,我们在学习完stack和queue后再来实现,因为涉及适配器的内容!
迭代器相关
//迭代器相关
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);
}
默认成员函数
//默认成员函数
//构造函数
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
//拷贝构造
list(const list<T>& lt)
{
_head= new Node;
_head->_next = _head;
_head->_prev = _head;
for (const auto& e : lt)
{
push_back(e);
}
}
//交换函数,交换两个链表数据
void swap(list<T>& lt)
{
::swap(_head, lt._head);
}
//赋值运算符重载
list<T>& operator=(list<T> x)
{
swap(x);
return *this;
}
容量相关
//容量相关
size_t size()const
{
auto it = begin();
size_t i = 0;
while (it != end())
{
i++;
it++;
}
return i;
}
bool empty()
{
return begin() == end();
}
访问相关
//访问相关
T& front()
{
return _head->_next->_data;
}
T& back()
{
return _head->_prev->_data;
}
修改相关
//头插
void push_front(const T& val)
{
insert(begin(), val);
}
//头删
void pop_front()
{
erase(begin());
}
//尾插
void push_back(const T& val)
{
insert(end(), val);
}
//尾删
void pop_back()
{
erase(--end());
}
//插入函数
iterator insert(iterator position, const T& val)
{
Node* cur = position._node;
Node* cur_prev = cur->_prev;
Node* newnode = new Node(val);
cur_prev->_next = newnode;
newnode->_prev = cur_prev;
newnode->_next = cur;
cur->_prev = newnode;
return iterator(newnode);
}
//删除函数
iterator erase(iterator position)
{
assert(position != end());
Node* cur = position._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = cur->_next;
next->_prev = cur->_prev;
delete cur;
return iterator(next);
}
//清除数据
void clear()
{
auto it = begin();
while (it != end())
{
it = erase(it);
}
}
tion._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = cur->_next;
next->_prev = cur->_prev;
delete cur;
return iterator(next);
}
//清除数据
void clear()
{
auto it = begin();
while (it != end())
{
it = erase(it);
}
}