【C++】一篇文章带你深入了解list

devtools/2024/10/20 5:40:21/

在这里插入图片描述

目录

  • 一、list的介绍
  • 二、 标准库中的list
    • 2.1 list的常见接口说明
      • 2.1.1 list对象的常见构造
        • 2.1.1.1 [无参构造函数](https://legacy.cplusplus.com/reference/list/list/list/)
        • 2.1.1.2 [有参构造函数(构造并初始化n个val)](https://legacy.cplusplus.com/reference/list/list/list/)
        • 2.1.1.3 [有参构造函数(使用迭代器进行初始化构造)](https://legacy.cplusplus.com/reference/list/list/list/)
        • 2.1.1.4 [拷贝构造函数](https://legacy.cplusplus.com/reference/list/list/list/)
      • 2.1.2 list iterator的使用
        • 2.1.2.1 [begin()](https://legacy.cplusplus.com/reference/list/list/begin/) + [end()](https://legacy.cplusplus.com/reference/list/list/end/)
        • 2.1.2.2 [rbegin()](https://legacy.cplusplus.com/reference/list/list/rbegin/) + [rend()](https://legacy.cplusplus.com/reference/list/list/rend/)
      • 2.1.3 list对象的容量操作
        • 2.1.3.1 [empty()函数](https://legacy.cplusplus.com/reference/list/list/empty/)
        • 2.1.3.2 [size()函数](https://legacy.cplusplus.com/reference/list/list/size/)
      • 2.1.4 list对象的增删查改及访问
        • 2.1.4.1 [push_front()函数](https://legacy.cplusplus.com/reference/list/list/push_front/)
        • 2.1.4.2 [pop_front()函数](https://legacy.cplusplus.com/reference/list/list/pop_front/)
        • 2.1.4.3 [push_back()函数](https://legacy.cplusplus.com/reference/list/list/push_back/)
        • 2.1.4.4 [pop_back()函数](https://legacy.cplusplus.com/reference/list/list/pop_back/)
        • 2.1.4.5 [insert()函数](https://legacy.cplusplus.com/reference/list/list/insert/)
        • 2.1.4.6 [erase()函数](https://legacy.cplusplus.com/reference/list/list/erase/)
        • 2.1.4.7 [swap()函数](https://legacy.cplusplus.com/reference/list/list/swap/)
        • 2.1.4.8 [clear()函数](https://legacy.cplusplus.com/reference/list/list/clear/)
        • 2.1.4.9 [front()函数](https://legacy.cplusplus.com/reference/list/list/front/) + [back()函数](https://legacy.cplusplus.com/reference/list/list/back/)
      • 2.1.5 list的迭代器失效
  • 三、list的模拟实现
    • 3.1 list 节点类的实现
    • 3.2 list 中默认成员函数的实现
    • 3.3 list 中 size、empty 和 swap 函数的实现
    • 3.4 list 中 迭代器类 的实现
    • 3.5 list 中 迭代器 、 范围构造函数 和 clear 函数 的实现
    • 3.6 list 中 insert 和 erase 的实现
    • 3.7 list 中 push_back、pop_back、push_front 和 pop_front 函数的实现
    • 3.8 list 中 反向迭代器类 和 反向迭代器 的实现
    • 3.9 list 实现汇总及函数测试
  • 四、 list 与 vector 的对比
  • 结尾

list_4">一、list的介绍

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

list_13">二、 标准库中的list

list_14">2.1 list的常见接口说明

list_16">2.1.1 list对象的常见构造

2.1.1.1 list/list/list/" rel="nofollow">无参构造函数
list();
int main()
{list<int> l;return 0;
}

在这里插入图片描述


2.1.1.2 list/list/list/" rel="nofollow">有参构造函数(构造并初始化n个val)
list (size_type n, const value_type& val = value_type());
int main()
{list<int> l(5, 4);return 0;
}

在这里插入图片描述


2.1.1.3 list/list/list/" rel="nofollow">有参构造函数(使用迭代器进行初始化构造)
template <class InputIterator>list (InputIterator first, InputIterator last);
int main()
{string s("Love");list<int> l(s.begin(), s.end());return 0;
}

在这里插入图片描述


2.1.1.4 list/list/list/" rel="nofollow">拷贝构造函数
list (const list& x);
int main()
{list<int> l1(5,6);list<int> l2(l1);return 0;
}

在这里插入图片描述


list_iterator_80">2.1.2 list iterator的使用

2.1.2.1 list/list/begin/" rel="nofollow">begin() + end()
	  iterator begin();
const_iterator begin() const;
获取第一个数据位置的iterator/const_iteratoriterator end();
const_iterator end() const;
获取最后一个数据的下一个位置的iterator/const_iterator
int main()
{list<int> l;for (int i = 0; i < 10; i++){l.push_back(i);}list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << ' ';++it;}cout << endl;return 0;
}

在这里插入图片描述


2.1.2.2 list/list/rbegin/" rel="nofollow">rbegin() + rend()
	  reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
获取最后一个数据位置的reverse_iterator/const_reverse_iterator reverse_iterator rend();
const_reverse_iterator rend() const;
获取第一个数据前一个位置的reverse_iterator/const_reverse_iterator 
int main()
{list<int> l;for (int i = 0; i < 10; i++){l.push_back(i);}list<int>::reverse_iterator it = l.rbegin();while (it != l.rend()){cout << *it << ' ';++it;}cout << endl;return 0;
}

在这里插入图片描述

注意

  1. beginend为正向迭代器,对迭代器执行++操作,迭代器向后移动
  2. rbeginrend为反向迭代器,对迭代器执行++操作,迭代器向前移动

list_155">2.1.3 list对象的容量操作

2.1.3.1 list/list/empty/" rel="nofollow">empty()函数
bool empty() const;         判断是否为空
int main()
{list<int> l;cout << l.empty() << endl;l.push_back(1);cout << l.empty() << endl;return 0;
}

在这里插入图片描述

2.1.3.2 list/list/size/" rel="nofollow">size()函数
size_type size() const;      获取数据个数
int main()
{list<int> l;cout << l.size() << endl;for (int i = 0; i < 10; i++){l.push_back(i);}cout << l.size() << endl;return 0;
}

list_193">2.1.4 list对象的增删查改及访问

2.1.4.1 list/list/push_front/" rel="nofollow">push_front()函数
void push_front (const value_type& val);  头插
int main()
{list<int> l;l.push_front(1);l.push_front(2);l.push_front(3);l.push_front(4);for (auto e : l){cout << e << ' ';}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.2 list/list/pop_front/" rel="nofollow">pop_front()函数
void pop_front();  头删

在这里插入图片描述


2.1.4.3 list/list/push_back/" rel="nofollow">push_back()函数
void push_back (const value_type& val);   尾插
int main()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);for (auto e : l){cout << e << ' ';}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.4 list/list/pop_back/" rel="nofollow">pop_back()函数
void pop_back();  尾删
int main()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);for (auto e : l){	cout << e << ' ';	}cout << endl;l.pop_back();for (auto e : l){	cout << e << ' ';	}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.5 list/list/insert/" rel="nofollow">insert()函数
iterator insert (iterator position, const value_type& val);
insert()函数能够在position之前插入val,并返回插入数据位置的 iterator void insert (iterator position, size_type n, const value_type& val);
insert()函数能够在position之前插入 n 个 val             template <class InputIterator>void insert (iterator position, InputIterator first, InputIterator last);
insert()函数能够在position之前插入一段迭代器区间的数据       		
int main()
{list<int> l;string s("Love");l.push_back(1);l.push_back(2);for (auto e : l){	cout << e << ' ';	}cout << endl;// insert()函数能够在position之前插入val,并返回插入数据位置的 iterator cout << *(l.insert(l.begin(), 20)) << endl;for (auto e : l){cout << e << ' ';}cout << endl;// insert()函数能够在position之前插入 n 个 val        l.insert(++l.begin() , 3 ,30);for (auto e : l){cout << e << ' ';}cout << endl;// insert()函数能够在position之前插入一段迭代器区间的数据       		l.insert(++l.begin(), s.begin() , s.end());for (auto e : l){cout << e << ' ';}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.6 list/list/erase/" rel="nofollow">erase()函数
iterator erase (iterator position);
erase()函数能够删除在position位的的数据,并返回删除数据后面数据位置的 iteratoriterator erase (iterator first, iterator last);
erase()函数能够删除在迭代器区间 [first,last) 的的数据,并返回删除数据后面数据位置的 iterator             
int main()
{list<int> l;for (int i = 0; i < 10; i++){l.push_back(i);}cout << endl;for (auto e : l){cout << e << ' ';}cout << endl;// erase()函数能够删除在position位的的数据// 并返回删除数据后面数据位置的 iteratorcout << *(l.erase(l.begin())) << endl;for (auto e : l){cout << e << ' ';}cout << endl;// erase()函数能够删除在迭代器区间 [first,last) 的的数据// 并返回删除数据后面数据位置的 iterator        cout << *(l.erase(++l.begin(),--l.end())) << endl;for (auto e : l){cout << e << ' ';}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.7 list/list/swap/" rel="nofollow">swap()函数
void swap (list& x);
交换两个list的数据空间
int main()
{list<int> l1(4, 10);list<int> l2(5, 5);for (auto e : l1){	cout << e << ' ';	}cout << endl;for (auto e : l2){	cout << e << ' ';	}cout << endl;l1.swap(l2);for (auto e : l1){	cout << e << ' ';	}cout << endl;for (auto e : l2){	cout << e << ' ';	}cout << endl;return 0;
}

在这里插入图片描述


2.1.4.8 list/list/clear/" rel="nofollow">clear()函数
void clear();
清除list中的有效数据
int main()
{list<int> l(4, 10);cout << l.size() << endl;l.clear();cout << l.size() << endl;return 0;
}

在这里插入图片描述


2.1.4.9 list/list/front/" rel="nofollow">front()函数 + back()函数
访问list中的第一个数据reference front();
const_reference front() const;访问list中的最后一个数据reference back();
const_reference back() const;
int main()
{list<int> l;for (int i = 0; i < 10; i++){l.push_back(i);}cout << "front:" << l.front() << endl;cout << "back:" << l.back() << endl;return 0;
}

在这里插入图片描述


list_475">2.1.5 list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

int main()
{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;}return 0;
}// 改正
int main()
{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_510">三、list的模拟实现

list__512">3.1 list 节点类的实现

namespace aj
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_val(val){}ListNode<T>* _prev = nullptr;ListNode<T>* _next = nullptr;T _val;};
};

list__534">3.2 list 中默认成员函数的实现

namespace aj
{//listtemplate<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:// List的构造list(){CreateHead();}// 构造并用n个val初始化list(int n, const T& value = T()){CreateHead();while (n--){push_back(value);}}// 链表的拷贝构造// list(const list<T>& l)list(list<T>& l){CreateHead();for (auto e : l){push_back(e);}}list<T>& operator=(const list<T> l){swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}void swap(list<T>& l){std::swap(_head, l._head);std::swap(_size, l._size);}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list__sizeempty__swap__613">3.3 list 中 size、empty 和 swap 函数的实现

namespace aj
{template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:size_t size()const{return size;}bool empty()const{return _head->_next == _head && _head->_prev == _head;}void swap(list<T>& l){std::swap(_head, l._head);std::swap(_size, l._size);}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list____656">3.4 list 中 迭代器类 的实现

namespace aj
{//List的迭代器类//template<class T>template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;// 成员变量PNode _pNode;public:// 迭代器的构造函数ListIterator(PNode pNode = nullptr):_pNode(pNode){}Ref operator*(){return _pNode->_val;}Ptr operator->(){return &(_pNode->_val);}Self& operator++(){_pNode = _pNode->_next;return *this;}Self operator++(int){Self tmp(*this);++* this;return tmp;}Self& operator--(){_pNode = _pNode->_prev;return *this;}Self operator--(int){Self tmp(*this);--* this;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}};
};

list______clear___728">3.5 list 中 迭代器 、 范围构造函数 和 clear 函数 的实现

namespace aj
{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&> const_iterator;template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(first._pNode->_val);++first;}}// List Iteratoriterator begin(){// return iterator(_head->_next);return _head->_next;}iterator end(){// return iterator(_head);return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}void clear(){list<T>::iterator lit = begin();while (lit != end()){lit = erase(lit);}}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list__insert__erase__802">3.6 list 中 insert 和 erase 的实现

namespace aj
{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&> const_iterator;// 在pos位置前插入值为val的节点,返回插入新节点的位置iterator insert(iterator pos, const T& val){// 通过迭代器找到所需的节点指针Node* cur = pos._pNode;Node* prev = cur->_prev;// 创建新的节点Node* newnode = new Node(val);// 节点间相互连接newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;newnode->_next = cur;// 节点数量++_size++;//return iterator(newnode);return newnode;}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(_size > 0);// 找到所需要的节点指针Node* cur = pos._pNode;Node* next = cur->_next;Node* prev = cur->_prev;// 节点相互连接next->_prev = prev;prev->_next = next;// 删除节点delete cur;cur = nullptr;// 减少节点数目--_size;// 返回删除节点的下一个位置// return iterator(next);return next;}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list__push_backpop_backpush_front__pop_front__880">3.7 list 中 push_back、pop_back、push_front 和 pop_front 函数的实现

namespace aj
{template<class T>class list{public:typedef ListNode<T> Node;typedef Node* PNode;void push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val); }void pop_front() { erase(begin()); }private:PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list______906">3.8 list 中 反向迭代器类 和 反向迭代器 的实现

反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。

注意:反向迭代器类可以被所有的容器封装成反向迭代器使用。

下面两种反向迭代器的实现虽然不同,但是功能是相同的。反向迭代器类的实现不同,那么对应封装迭代器的时候也要做出相应的改变。

在这里插入图片描述

reverse_iterator.h 反向迭代器非对称版本
#pragma once// 不对称版本
namespace aj
{// 适配器 -- 复用template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator,Ref,Ptr> Self;Reverse_iterator(const Iterator& it):_it(it){}Ref operator*(){return *_it;}Ptr operator->(){return _it.operator->();}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}Iterator _it;};
}
list.h 反向迭代器非对称版本
#include"reverse_iterator.h"namespace aj
{template<class T>class list{public:typedef ListNode<T> Node;typedef Node* PNode;public:// typedef ListIterator<T> iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;public:// reverse_iterator 不对称版本reverse_iterator rbegin(){// return iterator(_head->_next);return --end();    //这里可以使用--end()也可以使用end()-1,但是没有写operator-()}                      //这里就使用--end(),这里能使用--end()的原因是//end()返回传值返回的自定义类型的临时对象,具有常性,是常量//但是这里有编译器的特殊处理//使得const对象可以调用非const成员函数reverse_iterator rend(){// return iterator(_head);return end();}const_reverse_iterator rbegin()const{return --end();}const_reverse_iterator rend()const{return end();}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};
reverse_iterator.h 反向迭代器对称版本
#pragma once
// 对称版本
namespace aj
{// 适配器 -- 复用template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator,Ref,Ptr> Self;Reverse_iterator(const Iterator& it):_it(it){}Ref operator*(){Iterator tmp(_it);return *--tmp;}Ptr operator->(){return --_it.operator->();}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}Iterator _it;};
}
list.h 反向迭代器对称版本
#include"reverse_iterator.h"namespace aj
{template<class T>class list{public:typedef ListNode<T> Node;typedef Node* PNode;public:// typedef ListIterator<T> iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;public:// reverse_iterator 对称版本reverse_iterator rbegin(){// return iterator(_head->_next);return end();}reverse_iterator rend(){// return iterator(_head);return begin();}const_reverse_iterator rbegin()const{return end();}const_reverse_iterator rend()const{return begin();}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};
};

list__1182">3.9 list 实现汇总及函数测试

reverse_iterator.h
#pragma once// 不对称版本
//namespace aj
//{
//	// 适配器 -- 复用
//	template<class Iterator, class Ref, class Ptr>
//	struct Reverse_iterator
//	{
//		typedef Reverse_iterator<Iterator,Ref,Ptr> Self;
//
//		Reverse_iterator(const Iterator& it)
//			:_it(it)
//		{}
//
//		Ref operator*()
//		{
//			return *_it;
//		}
//
//		Ptr operator->()
//		{
//			return _it.operator->();
//		}
//
//		Self& operator++()
//		{
//			--_it;
//			return *this;
//		}
//
//		Self operator++(int)
//		{
//			Self tmp(*this);
//			--_it;
//			return tmp;
//		}
//
//		Self& operator--()
//		{
//			++_it;
//			return *this;
//		}
//
//		Self operator--(int)
//		{
//			Self tmp(*this);
//			++_it;
//			return tmp;
//		}
//
//		bool operator!=(const Self& s)
//		{
//			return _it != s._it;
//		}
//
//		bool operator==(const Self& s)
//		{
//			return _it == s._it;
//		}
//		Iterator _it;
//	};
//}// 对称版本
namespace aj
{// 适配器 -- 复用template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator,Ref,Ptr> Self;Reverse_iterator(const Iterator& it):_it(it){}Ref operator*(){Iterator tmp(_it);return *--tmp;}Ptr operator->(){return --_it.operator->();}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}Iterator _it;};
}
list.h
#pragma once#include<iostream>
#include<assert.h>
#include <string>
#include <vector>
using namespace std;#include"reverse_iterator.h"namespace aj
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_val(val){}ListNode<T>* _prev = nullptr;ListNode<T>* _next = nullptr;T _val;};//List的迭代器类//template<class T>template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T ,Ref , Ptr> Self;// 成员变量PNode _pNode;// typedef ListIterator<T, Ref, Ptr> Self;public:// 迭代器的构造函数ListIterator(PNode pNode = nullptr):_pNode(pNode){}Ref operator*(){return _pNode->_val;}Ptr operator->(){return &(_pNode->_val);}Self& operator++(){_pNode = _pNode->_next;return *this;}Self operator++(int){Self tmp(*this);++* this;return tmp;}Self& operator--(){_pNode = _pNode->_prev;return *this;}Self operator--(int){Self tmp(*this);--* this;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return _pNode == l._pNode;}};//listtemplate<class T>class list{public:typedef ListNode<T> Node;typedef Node* PNode;public:// typedef ListIterator<T> iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;typedef Reverse_iterator<const_iterator,const T&,const T*> const_reverse_iterator;public:///// List的构造list(){CreateHead();}list(int n, const T& value = T()){CreateHead();while (n--){push_back(value);}}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(first._pNode->_val);++first;}}// 链表的拷贝构造// list(const list<T>& l)list(list<T>& l){CreateHead();for (auto e : l){push_back(e);}}//list<T>& operator=(const list<T> l)list<T>& operator=(list<T> l){swap(l);return *this;}~list(){clear();delete _head;_head = nullptr;}///// List Iteratoriterator begin(){// return iterator(_head->_next);return _head->_next;}iterator end(){// return iterator(_head);return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;} reverse_iterator 不对称版本//reverse_iterator rbegin()//{//    // return iterator(_head->_next);//    return --end();    //这里可以使用--end()也可以使用end()-1,但是没有写operator-()//}                      //这里就使用--end(),这里能使用--end()的原因是//                       //end()返回传值返回的自定义类型的临时对象,具有常性,是常量//                       //但是这里有编译器的特殊处理//                       //使得const对象可以调用非const成员函数//reverse_iterator rend()//{//    // return iterator(_head);//    return end();//}//const_reverse_iterator rbegin()const//{//    return --end();//}//const_reverse_iterator rend()const//{//    return end();//}// reverse_iterator 对称版本reverse_iterator rbegin(){// return iterator(_head->_next);return end();}reverse_iterator rend(){// return iterator(_head);return begin();}const_reverse_iterator rbegin()const{return end();}const_reverse_iterator rend()const{return begin();}///// List Capacitysize_t size()const{return size;}bool empty()const{return _head->_next == _head && _head->_prev == _head;}// List AccessT& front(){assert(_head->_next != _head);return _head->_next->_val;}const T& front()const{assert(_head->_next != _head);return _head->_next->_val;}T& back(){assert(_head->_prev != _head);return _head->_prev->_val;}const T& back()const{assert(_head->_prev != _head);return _head->_prev->_val;}// List Modifyvoid push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点,返回插入新节点的位置iterator insert(iterator pos, const T& val){// 通过迭代器找到所需的节点指针Node* cur = pos._pNode;Node* prev = cur->_prev;// 创建新的节点Node* newnode = new Node(val);// 节点间相互连接newnode->_prev = prev;prev->_next = newnode;cur->_prev = newnode;newnode->_next = cur;// 节点数量++_size++;//return iterator(newnode);return newnode;}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(_size > 0);// 找到所需要的节点指针Node* cur = pos._pNode;Node* next = cur->_next;Node* prev = cur->_prev;// 节点相互连接next->_prev = prev;prev->_next = next;// 删除节点delete cur;cur = nullptr;// 减少节点数目--_size;// 返回删除节点的下一个位置// return iterator(next);return next;}void clear(){list<T>::iterator lit = begin();while (lit != end()){lit = erase(lit);}}void swap(list<T>& l){std::swap(_head, l._head);std::swap(_size, l._size);}private:void CreateHead(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}PNode _head;    // 头结点int _size;      // 记录链表中节点的个数};struct AA{AA(int a1 = 0 , int a2 = 0):_a1(a1),_a2(a2){}int _a1;int _a2;};//template<class T>//void print_list(const list<T>& l)//{//    // list<T>未实例化的类模板,编译器不能去他里面去找//    // 那么编译器就无法确定这里的//    // const_iterator是静态变量还是内嵌类型//    // 加上typename就相当于告诉编译器这里是内嵌类型//    // 等list<T>初始化后再到类中去取//    typename list<T>::const_iterator it = l.begin();//    while (it != l.end())//    {//        cout << *it << ' ';//        ++it;//    }//    cout << endl;//}template<class Container>void print_container(const Container& l){typename Container::const_iterator it = l.begin();while (it != l.end()){cout << *it << ' ';++it;}cout << endl;}///// 测试无参构造、n个val的构造、迭代器区间构造void test_list1(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);list<int> l1(10, 20);list<int> l2(++l1.begin(), --l1.end());for (auto e : l){cout << e << ' ';}cout << endl;for (auto e : l1){cout << e << ' ';}cout << endl;for (auto e : l2){cout << e << ' ';}cout << endl;}// 测试 insert push_back push_front// 测试 iterator 范围for// 测试 operator !=  operator* void test_list2(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);l.push_front(10);l.push_front(20);list<int>::iterator lit = l.begin();while (lit != l.end()){cout << *lit << ' ';++lit;}cout << endl;for (auto& e : l){e += 10;cout << e << ' ';}cout << endl;}// 测试 erase pop_back pop_frontvoid test_list3(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);for (auto e : l){cout << e << ' ';}cout << endl;l.pop_back();for (auto e : l){cout << e << ' ';}cout << endl;l.pop_front();for (auto e : l){cout << e << ' ';}cout << endl;}// 测试 operator++  operator++(int)// 测试 operator--  operator--(int)void test_list4(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);list<int>::iterator lit1 = l.begin();cout << *(lit1++) << endl;cout << *(++lit1) << endl;list<int>::iterator lit2 = l.end();cout << *(--lit2) << endl;cout << *(lit2--) << endl;cout << endl;}// 测试 operator==  operator!=void test_list5(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);list<int>::iterator lit = l.end();cout << (lit == lit) << endl;cout << (lit != lit) << endl;cout << endl;}void test_list6(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);for (auto e : l){cout << e << ' ';}cout << endl;cout << l.front() << ' ' << l.back() << endl;l.pop_back();l.pop_front();for (auto e : l){cout << e << ' ';}cout << endl;cout << l.front() << ' ' << l.back() << endl;l.pop_back();l.pop_front();for (auto e : l){cout << e << ' ';}cout << endl;cout << l.front() << ' ' << l.back() << endl;}// 测试 operator->void test_list7(){list<AA> l1;l1.push_back(AA(1, 1));l1.push_back(AA(2, 2));l1.push_back(AA(3, 3));l1.push_back(AA(4, 4));list<AA>::iterator it = l1.begin();while (it != l1.end()){cout << it->_a1 << ' ' << it->_a2 << endl;++it;}}// 测试拷贝构造和赋值重载  void test_list8                                                                      (){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);// 拷贝构造l2list<int> l2(l1);// 输出l1和l2的值for (auto e : l1){cout << e << ' ';}cout << endl;for (auto e : l2){cout << e << ' ';}cout << endl;// l2中的值都*10,并输出for (auto& e : l2){e *= 10;cout << e << ' ';}cout << endl;// 将l2赋值给l1l1 = l2;// 输出l1和l2的值for (auto e : l1){cout << e << ' ';}cout << endl;for (auto e : l2){cout << e << ' ';}cout << endl;}// 测试print_containervoid test_list9(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);print_container(l1);list<string> l2;l2.push_back("1111111111111111111");l2.push_back("2222222222222222222");l2.push_back("3333333333333333333");l2.push_back("4444444444444444444");print_container(l2);vector<string> v;v.push_back("1111111111111111111");v.push_back("2222222222222222222");v.push_back("3333333333333333333");v.push_back("4444444444444444444");print_container(v);}void test_list10(){list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);list<int>::reverse_iterator it = l1.rbegin();while (it != l1.rend()){cout << *it << ' ';++it;}cout << endl;}
};

list__vector__1999">四、 list 与 vector 的对比

vectorlist都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链
访问支持随机访问,访问某个元素的效率O(1)不支持随机访问,访问某个元素的效率为O(N)
插入和删除头部和中部的插入效率低,因为需要移动大量数据,效率为O(N),尾插和尾删的效率高,效率为O(1) 。插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置的插入和删除效率高,不需要移动数据,效率为O(N)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭 代 器 失 效在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使 用 场 景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹
在这里插入图片描述


http://www.ppmy.cn/devtools/10718.html

相关文章

matlab简单统计学预测方法分析

基础的统计学预测方法分析&#xff0c;内容参考国防工业出版社-司守奎&#xff0c;孙玺菁主编-《数学建模算法与应用&#xff08;第三版&#xff09;》。本文结合实际应用对文章内容进行了提取&#xff0c;结合matlab算法进行程序编写。 本文所涉及的所有代码内容可通过百度网…

五种主流数据库:集合运算

关系型数据库中的表与集合理论中的集合类似&#xff0c;表是由行&#xff08;记录&#xff09;组成的集合。因此&#xff0c;SQL 支持基于数据行的各种集合运算&#xff0c;包括并集运算&#xff08;Union&#xff09;、交集运算&#xff08;Intersect&#xff09;和差集运算&a…

苍穹外卖day7 缓存商品(redis/Spring Cache)、用户端购物车功能

文章目录 前言一、缓存菜品1. 问题说明2. 解决办法3. 代码开发 二、缓存套餐1. Spring Cache2. 实现思路 三、购物车管理1. 添加购物车1.1 产品原型1.2 接口设计1.3 数据库设计1.4 代码开发 2. 查看购物车2.1 接口设计2.2 代码开发 3. 清空购物车3.1 接口设计3.2 代码开发 4. 删…

go语言并发实战——日志收集系统(四) 利用tail包实现对日志文件的实时监控

Linux中的tail命令 tail 命令是一个在 Unix/Linux 操作系统上用来显示文件末尾内容的命令。它可以显示文件的最后几行内容&#xff0c;默认情况下显示文件的最后 10 行。tail 命令 非常有用&#xff0c;特别是在我们查看日志文件或者监视文件变化时。 基本用法如下&#xff1a…

Docker 基本管理

目录 Docker 概述 容器化越来越受欢迎&#xff0c;因为容器是&#xff1a; Docker与虚拟机的区别&#xff1a; 容器技术有哪些 容器在内核中支持2种重要技术&#xff1a; 六大namespace Docker核心概念&#xff1a; 你知道哪些云 华为云 、百度云 、移动云、 天翼云 、西…

【最新】生成式人工智能(AIGC)与大语言模型(LLM)学习资源汇总

基本概念学习 a) Andrej Karpathy 的 - 大型语言模型简介&#xff1a;https://www.youtube.com/watch?vzjkBMFhNj_g 该视频对 LLMs 进行了一般性和高级的介绍&#xff0c;涵盖推理、缩放、微调、安全问题和提示注入等主题。 b) Nvidia 的生成式 AI 介绍&#xff1a;Course …

【THM】Linux Privilege Escalation(权限提升)-初级渗透测试

介绍 权限升级是一个旅程。没有灵丹妙药,很大程度上取决于目标系统的具体配置。内核版本、安装的应用程序、支持的编程语言、其他用户的密码是影响您通往 root shell 之路的几个关键要素。 该房间旨在涵盖主要的权限升级向量,并让您更好地了解该过程。无论您是参加 CTF、参加…

C# AutoResetEvent

AutoResetEvent 是 C# 中的一个同步原语&#xff0c;用于在线程之间传递信号。当线程调用 AutoResetEvent 的 WaitOne 方法时&#xff0c;它会阻塞&#xff0c;直到另一个线程调用 Set 方法来释放它。一旦 WaitOne 方法返回&#xff0c;AutoResetEvent 将自动重置其状态&#x…