链表中每个节点的结构
每个节点都有一个prev,next,以及data
//list节点的结构
template<class T>
struct __list_node
{
//形参这样写的原因是,万一T是自定义类型,list<string>
__list_node(const T& x = T())
:_prev(nullptr)
, _next(nullptr)
, _data(x)
{}
__list_node<T>* _prev;
__list_node<T>* _next;
T _data;
};
链表的迭代器认识
vector和string的迭代器是原生指针,无论是解引用还是++,都可以得到自己想要的值。
链表的迭代器不能是原生指针了,链表的解引用是想要链表的值,++是想到下一个节点,那么假如是原生指针的话解引用是一个结构体,++是下一个结构体。等等,所以我们要通过重载运算符来模拟我们想要的行为。所以迭代器也被成为一种设计模式。对于不同的类,不需要知道你的内部实现,就可以对你进行访问和修改。
而对于赋值重载,需要实现深拷贝吗,不需要,我就是想要你那个节点的值。
析构函数,不需要自己实现,因为迭代器是访问数据,修改数据,并不是需要把那个节点删除.
源码中为什么迭代器的类模板要template<class T,class Ref,class Ptr>
命名为Ref,显然是想要你传引用,
命名为Ptr,显然是想要你传指针。
先来看看之前学的,string有两种迭代器,支持const对象迭代
typedef char* iterator,
typedef const char* iterator
vector迭代器有两种
typedef T* iterator
typedef const T* iterator
那么这里的List呢,由于原生指针的不适用,我们实现了一个迭代器类,里面封装了操作来模拟指针的操作。
照上面的想法,实现两种迭代器,还要实现两个类.
template<class T>
struct __list_iterator
{
typedef __list_iterator<T> self;
//相同操作
//访问变量操作
T& operator*()
{
return _node->_data;
}
}
template<class T>
struct __list_const_iterator
{
typedef __list_const_iterator<T> self;
//相同操作
//访问变量操作
const T& operator*()
{
return _node->_data;
}
}
而这两个类中部分操作一样,只是const迭代器类中,访问变量的那个函数多加了一个const修饰返回值让他不被修改,仅此而已.
假如List想要使用
template <class T>
class list
{
public:
typedef __list_iterator<T> iterator;
typedef __list_const_iterator<T> const_iterator;
...
private:
...
}
两个类大部分代码冗余,能不能用一个类呢,STL中提供了另一种很强的操作。
template<class T,class Ref,class Ptr>
struct __list_iterator
{
typedef __list_iterator<T> self;
//操作
//访问变量操作
Ref& operator*()
{
return _node->_data;
}
}
List中使用
template <class T,class Ref,class Ptr>
class list
{
public:
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_const_iterator<T,const T&,const T*> const_iterator;
...
private:
...
}
这也正体现了类设计复用。而传入ptr也是为了考虑当一个自定义类型没有重载输出时,用.
或者指针直接输出。本来应该是it.operator->()->x
即it->->x,为了易读,将它变成it->x
迭代器实现
//list迭代器的结构
//原生指针满足不了需求,所以需要自己写一个迭代器
template<class T,class Ref,class Ptr>
//在list插入操作时需要访问node来确定位置的前后节点,所以成员变量得是公有的
struct __list_iterator
{
typedef __list_iterator<T,Ref,Ptr> self;
typedef __list_node<T> node;
//节点构造
__list_iterator(node* node)
:_node(node)
{}
//不用实现赋值,拷贝构造,默认的浅拷贝即可。不用实现析构,默认的就可以(总不能把人家节点析构了吧)
//对于迭代器,节点指向同一个位置就相等,地址相等
bool operator!=(const self& s)const
{
return _node != s._node;
}
bool operator==(const self& s)const
{
return !(_node != s._node);
}
Ref operator*()const
{
return _node->_data;
}
//ptr为T*, _node->data为T类型,假如为自定义类型就可以访问他的成员变量了
Ptr operator->()const
{
return &(_node->_data)
}
//前置++
self& operator++()
{
//前置++,_node已经改变
_node=_node->_next;
return *this;
}
//后置++
self operator++(int)
{
self s(*this);
_node = _node->_next;
return s;
}
//前置--
self operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
self operator--(int)
{
self s(*this);
_node = _node->_prev;
return s;
}
node* _node;
};
整个链表的结构
每个链表默认给一个带头节点。
迭代器接口
迭代器就可以在这使用了
typedef __list_node<T> node;
public:
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
//迭代器接口
iterator begin()
{
//隐式类型转化成迭代器。
return _head->_next;
//return iterator(_head->_next);
//iterator it(_head->next) return it;
}
iterator end()
{
//最后一个节点的下一个位置,即_head.
return _head;
}
const_iterator begin()const
{
return _head->_next;
}
const_iterator end()const
{
return _head;
}
构造函数
无参构造
循环起来,开始啥都没有指向自己,node有默认构造函数
list()
{
//会调用节点的构造函数初始化
_head = new node;
_head->_next = _head;
_head->_prev = _head;
}
迭代器拷贝构造
//迭代器拷贝构造
template<class inputiterator>
list(inputiterator first, inputiterator last)
{
_head = new node;
_head->_next = _head;
_head->_prev = _head;
while (first != last)
{
push_back(*first);
++first;
}
}
拷贝构造
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_stage, v._end_of_stage);
}
利用已有的迭代器进行构造。
忘记了,竟然还想想写赋值重载那样形参写成传值调用,你拷贝构造。写传值就引发无穷递归了
list(const list<T>& l)
{
//不初始化头节点,直接和别人交换,就会导致执行temp的析构函数(析构了随机值)时崩溃
_head = new node;
_head->_next = _head;
_head->_prev = _head;
list<T> temp(l.begin(),l.end());
std::swap(_head, temp._head);
}
赋值重载
//赋值重载
list<T>& operator=(list<T> l)
{
std::swap(_head,l.head);
return *this;
}
析构函数
~list()
{
clear();
delete _head;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it=erase(it);
}
}
插入
插入不会引起迭代器失效,但是需要返回值来控制让pos指向新插入的那一个节点。
//在pos之前插入
iterator insert(iterator pos,const T& x)
{
node* newnode = new node(x);
node* cur = pos._node;
node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
//返回新插入的位置
return newnode;
}
删除
删除一定会引起当前迭代器失效,但不会影响其他,因为空间不连续。所以需要返回值来指向原来pos的下一个位置。
//删除
iterator erase(iterator pos)
{
//不能删头
assert(pos != end());
node* cur = pos._node;
node* prev = cur->_prev;
node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
return next;
}
链表实现代码
#include<iostream>
#include<assert.h>
#include<algorithm>
namespace zjn
{
//list节点的结构
template<class T>
struct __list_node
{
//形参这样写的原因是,万一T是自定义类型,list<string>
__list_node(const T& x = T())
:_prev(nullptr)
, _next(nullptr)
, _data(x)
{}
__list_node<T>* _prev;
__list_node<T>* _next;
T _data;
};
//list迭代器的结构
//原生指针满足不了需求,所以需要自己写一个迭代器
template<class T,class Ref,class Ptr>
//在list插入操作时需要访问node来确定位置的前后节点,所以成员变量得是公有的
struct __list_iterator
{
typedef __list_iterator<T,Ref,Ptr> self;
typedef __list_node<T> node;
//节点构造
__list_iterator(node* node)
:_node(node)
{}
//不用实现赋值,拷贝构造,默认的浅拷贝即可。不用实现析构,默认的就可以(总不能把人家节点析构了吧)
//对于迭代器,节点指向同一个位置就相等,地址相等
bool operator!=(const self& s)const
{
return _node != s._node;
}
bool operator==(const self& s)const
{
return !(_node != s._node);
}
Ref operator*()const
{
return _node->_data;
}
//ptr为T*, _node->data为T类型
Ptr operator->()const
{
return &(_node->_data)
}
//前置++
self& operator++()
{
//前置++,_node已经改变
_node=_node->_next;
return *this;
}
//后置++
self operator++(int)
{
self s(*this);
_node = _node->_next;
return s;
}
//前置--
self operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
self operator--(int)
{
self s(*this);
_node = _node->_prev;
return s;
}
node* _node;
};
//list链表的结构
template<class T>
class list
{
typedef __list_node<T> node;
public:
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
//迭代器接口
iterator begin()
{
//隐式类型转化成迭代器。
return _head->_next;
//return iterator(_head->_next);
//iterator it(_head->next) return it;
}
iterator end()
{
//最后一个节点的下一个位置,即_head.
return _head;
}
const_iterator begin()const
{
return _head->_next;
}
const_iterator end()const
{
return _head;
}
//构造接口
list()
{
//会调用节点的构造函数初始化
_head = new node;
_head->_next = _head;
_head->_prev = _head;
}
//迭代器拷贝构造
template<class inputiterator>
list(inputiterator first, inputiterator last)
{
_head = new node;
_head->_next = _head;
_head->_prev = _head;
while (first != last)
{
push_back(*first);
++first;
}
}
//拷贝构造(深拷贝)
//忘记了,竟然还想想写赋值重载那样形参写成传值调用,你写传值就引发无穷递归了
list(const list<T>& l)
{
//不初始化头节点,直接和别人交换,就会导致执行temp的析构函数(析构了随机值)时崩溃
_head = new node;
_head->_next = _head;
_head->_prev = _head;
list<T> temp(l.begin(),l.end());
std::swap(_head, temp._head);
}
//赋值重载
list<T>& operator=(list<T> l)
{
std::swap(_head,l.head);
return *this;
}
~list()
{
clear();
delete _head;
}
void clear()
{
iterator it = begin();
while (it != end())
{
it=erase(it);
}
}
//尾插
void push_back(const T& x)
{
//node* newnode = new node(x);
//node* tail = _head->_prev;
//tail->_next = newnode;
//newnode->_prev = tail;
//newnode->_next = _head;
//_head->_prev = newnode;
insert(end(),x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
// 1 2 3 4
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
//在pos之前插入
iterator insert(iterator pos,const T& x)
{
node* newnode = new node(x);
node* cur = pos._node;
node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
//返回新插入的位置
return newnode;
}
//删除
iterator erase(iterator pos)
{
//不能删头
assert(pos != end());
node* cur = pos._node;
node* prev = cur->_prev;
node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
return next;
}
private:
node* _head;
};
}