list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且可以前后双向迭代
list的底层式双向链表结构,双向链表中的每个元素存储在互不关联的独立节点中,节点中的指针指向前一个位置和后一个位置
list和forward_list非常相似:不同点在于,forward_list是单链表,只支持向前迭代,让其更加简单高效
与其他序列式容器相比(array,vector,deque),list通常在任意位置插入,删除元素的执行效率更好
list的最大缺陷在于不支持随机访问,要访问第六个元素,必须从头部或尾部遍历到该位置,在这段位置上需要线性时间的开销;list需要一些额外的空间,用于保存每个节点的相关联信息
构造
list(); // 构造空的list
list(size_type n, const value_type& val = value_type()); // 构造的list中包含n个值为val的值
list(const list& x); // 拷贝构造函数
list(InputIterator first, InputIterator last); // 用迭代器区间中的元素构造list
迭代器
list的迭代器不是原生的指针,而是通过封装之后的指针
在这里可以直接将迭代器理解为一个指针,该指针指向list中的某个节点
在实现前会将迭代器的封装讲一下实现思路
begin(); // 返回第一个元素的迭代器
end(); // 返回最后一个元素的下一个位置的迭代器
rbegin(); // 返回第一个元素的reverse_iterator,即end位置
rend(); // 返回最后一个元素的reverse_iterator,即begin位置
// (C++11) const迭代器
cbegin();
cend();
crbegin();
crend();
注:
begin和end为正向迭代器,对迭代器进行++操作,迭代器向后移动
rbegin和rend为反向迭代器,对迭代器进行++操作,迭代器向前移动
const系列迭代器,不允许更改值
容量
bool empty() const; // 检测list是否为空
size_t size() const; // 返回list中有效节点的数量
元素引用
reference front(); // 返回list第一个节点值的引用
const_reference front() const; // const引用
reference back(); // 返回list最后一个节点值的引用
const_reference back() const; // const引用
注:
reference为引用的重命名,使用typedef进行重命名
const_reference为const引用的重命名
修改
void push_front(const value_type& val); // 头插
void pop_front(); // 头删
void push_back(const value_type& val); // 尾插
void pop_back(); // 尾删
iterator insert(iterator position, const value_type& val); // 在pos位置进行插入
void insert(iterator position, size_type n, const value_type& val); //在pos位置插入n个val
void insert(iterator position,InputIterator first,InputIterator last);
// 插入[first, last)区间的元素
iterator erase(iterator position); // 删除pos位置的元素
iterator erase(iterator first, iterator last); // 删除[first,last)区间的元素
void swap(list& x); // 交换两个list中的元素
void resize(size_type n, value_type val = value_type());
// 将list有效元素改位n个,多出的元素用val填充
void clear(); // 清空list中的有效元素
迭代器失效即迭代器指向的节点被删除
list的底层结构为带头节点的双向循环链表,在list中进行插入是不会导致迭代器失效的
在删除的时候,只有删除的迭代器会失效,其他迭代器不受影响
#include
// list迭代器失效问题,在删除元素后,迭代器指向的节点已经释放,所以不能进行操作
void TestListIterator1() {
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
std::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 TestListIterator() {
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
std::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. 原生指针–vector; 2. 将原生指针进行封装
封装后的迭代器必须具备以下方法:
- 解引用,重载operator*();
- ->访问其指向空间的成员,迭代器必须重载operator->();
- 指针可以++向后移动,迭代器需要重载operator++(),operator++(int),如果是双向链表还需要重载–
- 迭代器需要进行必要,所以还需要重载operator==(), operator!=();
封装后的迭代器可通过类模板参数进行传入
// 正向迭代器的封装
template<class T, class Ref, class Ptr>
class ListIterator {
public:
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
: _pNode(pNode)
{}
ListIterator(const Self& l)
: _pNode(l._pNode)
{}
Ref operator*() {
return _pNode->_val;
}
Ptr operator->() {
return &(operator*());
}
Self& operator++() {
_pNode = _pNode->_next;
return *this;
}
Self operator++(int) {
Self tmp(*this);
_pNode = _pNode->_next;
return tmp;
}
Self& operator--() {
_pNode = _pNode->_prev;
return *this;
}
Self operator--(int) {
Self tmp(*this);
_pNode = _pNode->_prev;
return tmp;
}
bool operator!=(const Self& l) {
return _pNode != l._pNode;
}
bool operator==(const Self& l) {
return _pNode == l._pNode;
}
PNode _pNode;
};
// 反向迭代器的封装
template<class T, class Ref, class Ptr, class Iterator>
class ListReverseIterator {
typedef ListReverseIterator<T, Ref, Ptr, Iterator> Self;
public:
ListReverseIterator(const Iterator& it)
: _it(it)
{}
ListReverseIterator(const Self& s)
: _it(s._it)
{}
Ref operator*() {
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->() {
return &(operator*());
}
// 反向迭代器的++就是正向迭代器的--
Self& operator++() {
--_it;
return *this;
}
Self operator++(int) {
Iterator tmp(_it);
--_it;
return tmp;
}
Self& operator--() {
++_it;
return *this;
}
Self operator--(int) {
Iterator tmp(_it);
++_it;
return tmp;
}
bool operator!=(const Self& s) {
return _it != s._it;
}
bool operator==(const Self& s) {
return _it == s._it;
}
private:
Iterator _it;
};
#include
// 节点定义
template<class T>
struct ListNode
{
ListNode(const T& val = T())
: _prev(nullptr)
, _next(nullptr)
, _val(val)
{}
ListNode<T> *_prev;
ListNode<T> *_next;
T _val;
};
template<class T, class Ref, class Ptr>
class ListIterator {
public:
typedef ListNode<T>* PNode;
typedef ListIterator<T, Ref, Ptr> Self;
public:
ListIterator(PNode pNode = nullptr)
: _pNode(pNode)
{}
ListIterator(const Self& l)
: _pNode(l._pNode)
{}
Ref operator*() {
return _pNode->_val;
}
Ptr operator->() {
return &(operator*());
}
Self& operator++() {
_pNode = _pNode->_next;
return *this;
}
Self operator++(int) {
Self tmp(*this);
_pNode = _pNode->_next;
return tmp;
}
Self& operator--() {
_pNode = _pNode->_prev;
return *this;
}
Self operator--(int) {
Self tmp(*this);
_pNode = _pNode->_prev;
return tmp;
}
bool operator!=(const Self& l) {
return _pNode != l._pNode;
}
bool operator==(const Self& l) {
return _pNode == l._pNode;
}
PNode _pNode;
};
template<class T, class Ref, class Ptr, class Iterator>
class ListReverseIterator {
typedef ListReverseIterator<T, Ref, Ptr, Iterator> Self;
public:
ListReverseIterator(const Iterator& it)
: _it(it)
{}
ListReverseIterator(const Self& s)
: _it(s._it)
{}
Ref operator*() {
Iterator tmp = _it;
return *(--tmp);
}
Ptr operator->() {
return &(operator*());
}
// 反向迭代器的++就是正向迭代器的--
Self& operator++() {
--_it;
return *this;
}
Self operator++(int) {
Iterator tmp(_it);
--_it;
return tmp;
}
Self& operator--() {
++_it;
return *this;
}
Self operator--(int) {
Iterator tmp(_it);
++_it;
return tmp;
}
bool operator!=(const Self& s) {
return _it != s._it;
}
bool operator==(const Self& s) {
return _it == s._it;
}
private:
Iterator _it;
};
template<class T>
class List {
typedef ListNode<T> Node;
typedef Node* PNode;
public:
typedef ListIterator<T, T&, T*> Iterator;
typedef ListIterator<T, const T&, const T*> ConstIterator;
typedef ListReverseIterator<T, T&, T*, Iterator> ReverseIterator;
typedef ListReverseIterator<T, const T&, const T*, ConstIterator> ConstReverseIterator;
public:
List() {
CreateHeap();
}
List(int n, const T& value = T()) {
CreateHeap();
for (int i = 0; i < n; ++i)
{
push_back(value);
}
}
template<class Iterator>
List(Iterator first, Iterator last) {
CreateHeap();
while (first != last)
{
push_back(*first);
++first;
}
}
List(const List<T>& l) {
CreateHeap();
List<T> tmp(l.CBegin(), l.CEnd());
this->Swap(tmp);
}
List<T>& operator=(const List<T>& l) {
if (this != &l)
{
List<T> tmp(l);
this->Swap(tmp);
}
return *this;
}
~List() {
Clear();
delete _pHead;
_pHead = nullptr;
}
// Iterator
Iterator Begin() {
return Iterator(_pHead->_next);
}
Iterator End() {
return Iterator(_pHead);
}
ReverseIterator RBegin() {
return ReverseIterator(End());
}
ReverseIterator REnd() {
return ReverseIterator(Begin());
}
ConstIterator CBegin() const {
return ConstIterator(_pHead->_next);
}
ConstIterator CEnd() const {
return ConstIterator(_pHead);
}
ConstReverseIterator CRBegin() const {
return ConstReverseIterator(CEnd());
}
ConstReverseIterator CREnd() const {
return ConstReverseIterator(CBegin());
}
// list capacity
size_t Size() const {
size_t count = 0;
PNode pCur = _pHead->_next;
while (pCur != _pHead)
{
++count;
pCur = pCur->_next;
}
return count;
}
bool Empty() const {
return _pHead->_next == pHead;
}
void ReSize(size_t newSize, const T& val = T());
// list access
T& Front() {
return _pHead->_next->_val;
}
const T& Front() const {
return _pHead->_next->_val;
}
T& Back() {
return _pHead->_prev->_val;
}
const T& Back() const {
return _pHead->_prev->_val;
}
// list modify
void push_back(const T& val) {
PNode pNewNode = new Node(val);
pNewNode->_next = _pHead;
pNewNode->_prev = _pHead->_prev;
_pHead->_prev = _pHead;
pNewNode->_prev = _pHead->_prev;
_pHead->_prev = pNewNode;
pNewNode->_prev->_next = pNewNode;
}
void pop_back() {
PNode pDel = _pHead->_prev;
if (pDel != _pHead)
{
_pHead->_prev = pDel->_prev;
pDel->_prev->_next = _pHead;
delete pDel;
}
}
void push_front(const T& val) {
PNode pNewNode = new Node(val);
pNewNode->_next = _pHead->_next;
pNewNode->_prev = _pHead;
_pHead->_next = pNewNode;
pNewNode->_next->_prev = pNewNode;
}
void pop_front() {
PNode pDel = _pHead->_next;
if (pDel != _pHead)
{
_pHead->_next = pDel->_next;
pDel->_next->_prev = _pHead;
delete pDel;
}
}
Iterator insert(Iterator pos, const T& val) {
PNode pNewNode = new Node(val);
PNode pCur = pos._pNode;
pNewNode->_prev = pCur->_prev;
pNewNode->_next = pCur;
pNewNode->_prev->_next = pNewNode;
pCur->_prev = pNewNode;
return Iterator(pNewNode);
}
Iterator erase(Iterator pos) {
PNode pDel = pos._pNode;
PNode pRet = pDel->_next;
pDel->_prev->_next = pDel->_next;
pDel->_next->_prev = pDel->_prev;
delete pDel;
return Iterator(pRet);
}
void Clear() {
PNode pCur = _pHead->_next;
while (pCur != _pHead)
{
_pHead->_next = pCur->_next;
delete pCur;
pCur = _pHead->_next;
}
_pHead->_next = _pHead;
_pHead->_prev = _pHead;
}
void Swap(List<T>& l) {
std::swap(_pHead, l._pHead);
}
private:
void CreateHeap() {
_pHead = new Node;
_pHead->_next = _pHead;
_pHead->_prev = _pHead;
}
private:
PNode _pHead;
};
template<class T>
void PrintList(List<T>& l) {
auto it = l.Begin();
while (it != l.End())
{
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
}
template<class T>
void PrintListReverse(const List<T>& l) {
auto it = l.CRBegin();
while (it != l.CREnd())
{
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
}
void TestList1() {
List<int> l1;
List<int> l2(10, 5);
PrintList(l2);
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
List<int> l3(array, array + sizeof(array) / sizeof(array[0]));
PrintList(l3);
List<int> l4(l3);
PrintList(l4);
l1 = l4;
PrintList(l1);
PrintListReverse(l1);
}
int main()
{
TestList1();
return 0;
}