一. list 的介绍
- list 是可以在常数时间内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list 的底层是双向带头链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list 与forward_list非常相似:最主要的不同在于 forward_list 是单链表,只能朝前迭代,使其更简单高效。
- 与其他的序列式容器(array, vector, deque)相比,list 通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list 和 forward_list 最大的缺陷是不支持任意位置的随机访问。比如:要访问 list 的第 6 个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list 还需要一些额外的空间,以保存每个节点的相关联信息。
1. list 常见的重要接口
begin 与 end 为正向迭代器,对迭代器执行 ++ 操作,迭代器向后移动。rbegin(end) 与 rend(begin) 为反向迭代器,对迭代器执行 ++ 操作,迭代器向前移动。
2. list 的迭代器失效
迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为 list 的底层结构为带头结点的双向循环链表,因此在 list 中进行插入时是不会导致 list 的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
二. list 常用接口的模拟实现(含注释)
#include <assert.h>
#include <iostream>
using std::cout;
using std::endl;
namespace wch {
// 由于 list 中的 val 支持多种类型,定义模板参数 T
template<class T>
struct list_node {
list_node<T>* _next;
list_node<T>* _prev;
T _val;
// T(), 针对自定义类型会去调用它的构造函数,针对内置类型无影响
list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}
};
// 此处定义多个模板参数针对返回值类型
< , , >
{
list_node<T> Node;
__list_iterator<T, Ref, Ptr> self;
Node* _node;
__list_iterator(Node* node):_node(node){}
Ref *()
{ _node->_val; }
Ptr ->()
{ &_node->_val; }
self& ++()
{
_node = _node->_next;
*;
}
self ++()
{
;
_node = _node->_next;
tmp;
}
self& --()
{
_node = _node->_prev;
*;
}
self --()
{
;
_node = _node->_prev;
tmp;
}
!=( self& it)
{ _node != it._node; }
==( self& it)
{ _node == it._node; }
};
< >
{
list_node<T> Node;
:
__list_iterator<T, T&, T*> iterator;
__list_iterator<T, T&, T*> const_iterator;
{
(_head->_next);
}
{
_head;
}
{
(_head->_next);
}
{
_head;
}
{
_head = Node;
_head->_prev = _head;
_head->_next = _head;
_size = ;
}
()
{ (); }
( list<T>& lt)
{
();
(& e : lt)
(e);
}
{
std::(_head, lt._head);
std::(_size, lt._size);
}
list<T>& =(list<T> lt)
{
(lt);
*;
}
~()
{
();
_head;
_head = ;
}
{
iterator it = ();
(it != ()){
it = (it);
}
_size = ;
}
{ ((), x); }
{ ((), x); }
{ (--()); }
{ (()); }
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = (x);
prev->_next = newnode;
newnode->_next = cur;
cur->_prev = newnode;
newnode->_prev = prev;
++_size;
newnode;
}
{
(pos != ());
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
cur;
--_size;
next;
}
{
_size;
}
:
Node* _head;
_size;
};
{
list<>::const_iterator it = lt.();
(it != lt.()){
cout << *it << ;
++it;
}
cout << endl;
}
{
list<> lt;
lt.();
lt.();
lt.();
lt.();
list<>::iterator it = lt.();
(it != lt.()){
(*it)+=;
cout << *it << ;
++it;
}
cout << endl;
( e : lt){ cout << e << ; }
cout << endl;
(lt);
}
{
( a1 = , a2 = ):_a1(a1),_a2(a2){}
_a1;
_a2;
};
{
list<A> lt;
lt.((,));
lt.((,));
lt.((,));
lt.((,));
list<A>::iterator it = lt.();
(it != lt.()){
cout << it->_a1 << << it->_a2 << endl;
++it;
}
cout << endl;
}
{
list<> lt;
lt.();
lt.();
lt.();
lt.();
lt.();
lt.();
lt.();
lt.();
( e : lt){ cout << e << ; }
cout << endl;
lt.();
lt.();
( e : lt){ cout << e << ; }
cout << endl;
lt.();
lt.();
lt.();
lt.();
lt.();
( e : lt){ cout << e << ; }
cout << endl;
cout << lt.() << endl;
}
{
list<> lt;
lt.();
lt.();
lt.();
lt.();
( e : lt){ cout << e << ; }
cout << endl;
list<>(lt);
( e : lt1){ cout << e << ; }
cout << endl;
list<> lt2;
lt();
lt();
lt();
lt();
( e : lt2){ cout << e << ; }
cout << endl;
lt1 = lt2;
( e : lt1){ cout << e << ; }
cout << endl;
}
}


