1. List的介绍及使用
1.1 list的介绍
List的使用文档: list - C++ Reference
list可以看作是一个带头结点的双向循环链表

1.2 list的使用
list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已
达到可扩展的能力。以下为list中一些常见的重要接口。
1.2.1 list的构造


上面定义了三个类:本文介绍的List类,List的组成元素结点list_node以及List的迭代器list_iterator,后续它们的用法本文详细补充
list的构造:

list类
cpp
void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->prev = _head;
}
list()
{
empty_init(); // 空表初始化
}
cpp
// initializer_list直接{}初始化
list(initializer_list<T> il)
{
empty_init();
for (auto& e : v)
{
push_back(e);
}
}
// 迭代器区间初始化
template<class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
// n个元素初始化
list(size_t n, T val = T())
{
empty_init();
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
push_back函数和insert函数
cpp
void push_back(const T& x)
{
insert(end(), x);
}
void insert(iterator pos, const T& x)
{
Node* cur = pos._node;
Node* prev = cur->prev;
Node* newnode = new Node(x);
// prev newnode cur
prev->next = newnode;
newnode->prev = prev;
newnode->next = cur;
cur->prev = newnode;
++size;
}
list拷贝构造和赋值拷贝的传统和现代写法:
list类:
cpp
// 传统写法
// 拷贝构造
// lt2(lt1)
list(const list<T>& lt)
{
empty_init();
for (auto& e : lt)
{
push_back(e);
}
}
// 赋值拷贝
list<T>& operator=(const list<T>& lt)
{
if (this != <)
{
clear();
for (auto& e : lt)
{
push_back(e);
}
}
return *this;
}
// 现代写法
//list(list<T>& lt),拷贝构造
list(const list<T>& lt)
{
empty_init();
list tmp(lt.begin(), lt.end());
swap(tmp);
}
// list<T>& operator=(list<T> tmp),赋值拷贝
list& operator=(list<T> tmp)
{
swap(tmp);
return *this;
}
void swap(list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}
1.2.2 list iterator的使用(重点)
此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点

迭代器的设计是一种封装,封装隐藏底层的结构差异提供类似的统一方式访问容器
cpp
template<class T,class Ref>
struct list_iterator
{
using Self = list_iterator<T, Ref>; // 迭代器
using Node = list_node<T>; // 结点
Node* _node; // 结点的指针
list_iterator(Node* node)
:_node(node)
{}
// *it = 1
Ref operator*()
{
return _node->_data;
}
// ++it
Self& operator++()
{
_node = _node->_next;
return *this;
}
//it++
Self operator++(int) //为了与后置++做区分
{
Self tmp(*this); // 1. 先保存当前状态的副本
_node = _node->next; //2. 再移动指针
return tmp; //3. 返回副本(注意:不是引用!)
}
// --it
Self& operator--()
{
_node = _node->_prev;
return *this;
}
//it--
Self operator--(int) //为了与后置++做区分
{
Self tmp(*this); // 1. 先保存当前状态的副本
_node = _node->prev; //2. 再移动指针
return tmp; //3. 返回副本(注意:不是引用!)
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};


2. List的模拟实现
2.1 list类
结点:
cpp
template<class T>
struct list_node
{
list_node<T>* _next;
list_node<T>* _prev;
T _data;
list_node(const T& x = T()) // 匿名对象初始化
:_next(nullptr)
,_prev(nullptr)
,_data(x)
{}
};
list类:
cpp
template<class T>
class list
{
using Node = list_node<T>;
public:
using iterator = list_iterator<T, T&>;
using const_iterator = list_iterator<T, const T&>;
// 之前的写法
/* using iterator = list_iterator<T, T&>;
using const_iterator = list_iterator<T, const T&>;*/
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);
}
void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
list()
{
empty_init(); // 空表初始化
}
// initializer_list直接{}初始化
list(initializer_list<T> il)
{
empty_init();
for (auto& e : il)
{
push_back(e);
}
}
// 迭代器区间初始化
template<class InputIterator>
list(InputIterator first, InputIterator last)
{
empty_init();
while (first != last)
{
push_back(*first);
++first;
}
}
// n个元素初始化
list(size_t n, T val = T())
{
empty_init();
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
list(int n, T val = T())
{
empty_init();
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
~list()
{
clear();
delete _head;
_head = nullptr; // 为了防止访问野指针
_size = 0;
}
// 传统写法
// 拷贝构造
// lt2(lt1)
list(const list<T>& lt)
{
empty_init();
for (auto& e : lt)
{
push_back(e);
}
}
// 赋值拷贝
list<T>& operator=(const list<T>& lt)
{
if (this != <)
{
clear();
for (auto& e : lt)
{
push_back(e);
}
}
return *this;
}
//// 现代写法
////list(list<T>& lt),拷贝构造
//list(const list<T>& lt)
//{
// empty_init();
// list tmp(lt.begin(), lt.end());
// swap(tmp);
//}
//// list<T>& operator=(list<T> tmp),赋值拷贝
//list& operator=(list<T> tmp)
//{
// swap(tmp);
// return *this;
//}
void swap(list<T>& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}
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;
//}
void push_back(const T& x)
{
insert(end(), x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
iterator erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
--_size;
//return iterator(next);
return next; //结点的指针可以隐式类型转换成迭代器
}
void insert(iterator pos, const T& x)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = new Node(x);
// prev newnode cur
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
++_size;
}
size_t size() const
{
/*size_t n = 0;
for (auto& e : *this)
{
++n;
}
return n;*/
return _size;
}
private:
Node* _head;
size_t _size = 0;
};
3. List与vector的对比
两者的迭代器类型不同,
list:

vector:

只支持单向访问的迭代器:

迭代器从功能的角度可以分为:
(1)单向:++
(2)双向:++/--
(3)随机:++/--/+/-
因为sort排序函数只支持随机迭代器,所以list无法用sort函数,但是sort内部自己实现了sort排序函数,但是效率较于vector低很多


cpp
void test_op1()
{
srand(time(0));
const int N = 1000000;
list<int> lt1;
vector<int> v;
for (int i = 0; i < N; ++i)
{
auto e = rand() + i;
lt1.push_back(e);
v.push_back(e);
}
int begin1 = clock();
//
sort(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
lt1.sort();
int end2 = clock();
printf("vector sort:%d\n", end1 - begin1); // 输出 vector 排序耗时
printf("list sort : %d\n", end2 - begin2); // 输出 list 排序耗时
}

vector更适合排序
示例代码:
cpp
void test_op2()
{
srand(time(0));
const int N = 1000000;
list<int> lt1;
list<int> lt2;
for (int i = 0; i < N; ++i)
{
auto e = rand() + i;
lt1.push_back(e);
lt2.push_back(e);
}
int begin1 = clock();
// vector
vector<int> v(lt2.begin(), lt2.end());
//
sort(v.begin(), v.end());
// lt2
lt2.assign(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
lt1.sort();
int end2 = clock();
printf("list copy vector sort copy list sort:%d\n", end1 - begin1);
printf("list sort:%d\n", end2 - begin2);
}

