一、list的介绍
1、list是序列容器,允许在序列内的任何位置执行恒定时间的插入和删除操作,以及双向迭代。
2、list底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个节点和后一个节点。
3、list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能向前迭代,以让其更简单高效。
4、与其它容器相比(array,vector,deque)相比,list通常在任意位置进行插入、删除元素的执行效率更好。
5、与其它序列容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销:list还需要一些额外的空间,以保存每个节点的相关信息。
二、list的使用
1、list的构造
构造函数(constructor) | 接口说明 |
list(size_type n,const value_type& val=value_type()) | 构造的list中包含n个值为val的元素 |
list() | 构造空的 list |
list(cosnt list& x) | 拷贝构造函数 |
list(InputIterator frist,InputIterator last) | 用迭代器区间中的元素构造list |
2、list iterator的使用
函数声明 | 接口说明 |
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 | |
返回第一个元素的reverse_iterator,即end位置,返回最后一个元素的下一个位置的reverse_iterator,即begin位置 |
注意:
- begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动。
- rbegin与rend为反向迭代器,对迭代器执行++操作,迭代器向前移动。
3、list capacity
函数声明 | 接口说明 |
检测list是否为空 | |
返回list中有效节点的个数 |
4、list element access
函数声明 | 接口说明 |
返回list的第一个节点中值的引用 | |
返回list的最后一个节点中值的引用 |
5、list modiflers
函数声明 | 接口说明 |
在list首元素前插入值为val的元素 | |
删除list中第一个元素 | |
在list尾部插入值为val的元素 | |
删除list中最后一个元素 | |
在list pos位置中插入值为val的元素 | |
删除list pos位置的元素 | |
交换两个list中的元素 | |
清空list中的有效元素 |
三、list的迭代器失效
迭代器失效即迭代器所指向的节点无效,及该节点被删除了。因为list的底层结构为带头双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的。只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
void Test11()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,
//在下一次使用it时,必须先给其赋值
l.erase(it);
++it;
}
}
//改正
void Test12()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
l.erase(it++); // it = l.erase(it);
}
}
四、list类的模拟实现
1、节点结构
template<class T>
struct list_node//节点结构
{
list_node<T>* _prev;//指向前一个节点
list_node<T>* _next;//指向后一个节点
T _val;//存储数据
list_node(const T& x = T())//初始化
: _prev(nullptr)
, _next(nullptr)
, _val(x)
{}
};
2、迭代器结构
因为list是链表,它的节点空间是不连续的,没办法用原生指针直接实现迭代器,我们需要专门写一个结构体来定义迭代器。
//用模板可以同时实现const_iterator和iterator
template <class T, class Ref, class Ptr>//迭代器
struct list_iterator
{
typedef list_node<T> Node;
typedef list_iterator<T,Ref,Ptr> Self;
Node* _node;//指向数据
//需要传指向节点的指针,对迭代器的操作,实际上就是对这个指针进行操作
list_iterator(Node* node)
:_node(node)
{}
//运算符重载
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;
}
//如果这里的Ref是const T&类型的,那返回的内容就是无法修改
//如果这里的Ref是T&类型的,那返回的内容就可以修改
Ref operator*()//*迭代器
{
return _node->_val;
}
//如果这里的Ref是const T*类型的,那返回的内容就是无法修改
//如果这里的Ref是T*类型的,那返回的内容就可以修改
Ptr operator->()//迭代器->
{
return &_node->_val;
}
bool operator==(const Self& s)const//迭代器==迭代器
{
return _node == s._node;
}
bool operator!=(const Self& s)const//迭代器!=迭代器
{
return _node != s._node;
}
};
3、list的成员变量
template<class T>
class list//链表结构
{
public:
typedef list_node<T> Node;//节点
typedef list_iterator<T, T&, T*> iterator;//迭代器
typedef list_iterator<T, const T&, const T*> const_iterator;//const迭代器
//注意:const iterator并不是我们想要的const迭代器,这样写,是迭代器无法移动
//我们希望const迭代器可以移动,但是const迭代器指向的节点不能修改
private:
Node* _phead;//节点
size_t _size;//个数
};
4、空初始化与构造函数
void empty_init()//空初始化
{
_phead = new Node;
_size = 0;
_phead->_prev = _phead->_next = _phead;
}
list()//构造函数
{
empty_init();
}
list(const list<T>& l)//拷贝构造
{
empty_init();
for (auto a : l)
{
push_back(a);
}
}
5、swap函数与赋值重载函数
void swap(list<T>& l)//交换
{
std::swap(_phead, l._phead);
std::swap(_size, l._size);
}
list<T>& operator=(const list<T>& l)//赋值重载
{
list<T> tmp(l);
swap(tmp);
return *this;
}
6、迭代器
//迭代器
iterator begin()
{
iterator ret(_phead->_next);
return ret;
}
const_iterator begin()const
{
const_iterator ret(_phead->_next);
return ret;
}
iterator end()
{
iterator ret(_phead);
return ret;
}
const_iterator end()const
{
const_iterator ret(_phead);
return ret;
}
7、erase函数与pop_back函数与pop_front函数
iterator erase(iterator pos)//删除
{
assert(pos != end());
//记录前后节点
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
//释放当前节点
delete cur;
//连接前后节点
prev->_next = next;
next->_prev = prev;
--_size;
return next;
}
void pop_back()//尾删
{
erase(--end());
}
void pop_front()//头删
{
erase(begin());
}
8、clear函数与析构函数
void clear()//清空
{
auto cur = begin();
while (cur != end())//删除除了头结点以外的所以节点
{
cur = erase(cur);
}
}
~list()//析构函数
{
clear();//清空
delete _phead;//把头结点也处理了
_phead = nullptr;
_size = 0;
}
9、insert函数与push_back函数与push_front函数
iterator insert(iterator pos, const T& x = T())//插入
{
Node* newnode = new Node(x);//开新节点
//记录前后节点
Node* next = pos._node;
Node* prev = next->_prev;
//连接节点
newnode->_next = next;
newnode->_prev = prev;
prev->_next = newnode;
next->_prev = newnode;
++_size;
return newnode;
}
void push_back(const T& x)//尾插
{
insert(end(), x);
}
void push_front(const T& x)//头插
{
insert(begin(), x);
}
10、empty函数与size函数
bool empty()//判空
{
return _size == 0;
}
size_t size()//返回size
{
return _size;
}
11、其他的构造函数
list(int n, const T& x = T())//n个x构造
{
empty_init();
assert(n >= 0);
while (n--)
{
push_back(x);
}
}
template<class Iterator>
list(Iterator frist, Iterator last)//迭代器区间构造
{
empty_init();
while (frist != last)
{
push_back(*frist);
++frist;
}
}
12、完整代码
#include<iostream>
#include<assert.h>
using namespace std;
namespace lsx
{
template<class T>
struct list_node//节点结构
{
list_node<T>* _prev;//指向前一个节点
list_node<T>* _next;//指向后一个节点
T _val;//存储数据
list_node(const T& x = T())
: _prev(nullptr)
, _next(nullptr)
, _val(x)
{
}
};
//用模板可以同时实现const_iterator和iterator
template <class T, class Ref, class Ptr>//迭代器
struct list_iterator
{
typedef list_node<T> Node;
typedef list_iterator<T,Ref,Ptr> Self;
Node* _node;//指向数据
list_iterator(Node* node)//需要传指向节点的柱子很
:_node(node)
{}
//运算符重载
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;
}
Ref operator*()//*迭代器
{
return _node->_val;
}
Ptr operator->()//迭代器->
{
return &_node->_val;
}
bool operator==(const Self& s)const//迭代器==迭代器
{
return _node == s._node;
}
bool operator!=(const Self& s)const//迭代器!=迭代器
{
return _node != s._node;
}
};
template<class T>
class list//链表结构
{
public:
typedef list_node<T> Node;//节点
typedef list_iterator<T, T&, T*> iterator;//迭代器
typedef list_iterator<T, const T&, const T*> const_iterator;//const迭代器
//注意:const iterator并不是我们想要的const迭代器,这样写,是迭代器无法移动
//我们希望const迭代器可以移动,但是const迭代器指向的节点不能修改
void empty_init()//空初始化
{
_phead = new Node;
_size = 0;
_phead->_prev = _phead->_next = _phead;
}
list()//构造函数
{
empty_init();
}
list(int n, const T& x = T())//n个x构造
{
empty_init();
assert(n >= 0);
while (n--)
{
push_back(x);
}
}
template<class Iterator>
list(Iterator frist, Iterator last)//迭代器区间构造
{
empty_init();
while (frist != last)
{
push_back(*frist);
++frist;
}
}
list(const list<T>& l)//拷贝构造
{
empty_init();
for (auto a : l)
{
push_back(a);
}
}
list<T>& operator=(const list<T>& l)//赋值重载
{
list<T> tmp(l);
swap(tmp);
return *this;
}
~list()//析构函数
{
clear();
delete _phead;
_phead = nullptr;
_size = 0;
}
//迭代器
iterator begin()
{
iterator ret(_phead->_next);
return ret;
}
const_iterator begin()const
{
const_iterator ret(_phead->_next);
return ret;
}
iterator end()
{
iterator ret(_phead);
return ret;
}
const_iterator end()const
{
const_iterator ret(_phead);
return ret;
}
void clear()//清空
{
auto cur = begin();
while (cur != end())//删除除了头结点以外的所以节点
{
cur = erase(cur);
}
}
iterator erase(iterator pos)//删除
{
assert(pos != end());
//记录前后节点
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
//释放当前节点
delete cur;
//连接前后节点
prev->_next = next;
next->_prev = prev;
--_size;
return next;
}
void pop_back()//尾删
{
erase(--end());
}
void pop_front()//头删
{
erase(begin());
}
iterator insert(iterator pos, const T& x = T())//插入
{
Node* newnode = new Node(x);//开新节点
//记录前后节点
Node* next = pos._node;
Node* prev = next->_prev;
//连接节点
newnode->_next = next;
newnode->_prev = prev;
prev->_next = newnode;
next->_prev = newnode;
++_size;
return newnode;
}
void push_back(const T& x)//尾插
{
insert(end(), x);
}
void push_front(const T& x)//头插
{
insert(begin(), x);
}
void swap(list<T>& l)
{
std::swap(_phead, l._phead);
std::swap(_size, l._size);
}
bool empty()//判空
{
return _size == 0;
}
size_t size()//返回size
{
return _size;
}
private:
Node* _phead;//节点
size_t _size;//个数
};
}
如有错误,欢迎指正,谢谢。
完结。。。。
标签:node,const,iterator,迭代,实现,list,next,模拟 From: https://blog.51cto.com/u_15855358/7191858