湖南建设银行网站是多少,天津网址,wordpress帖子添加代码,网站设置关键字文章目录 一、list源码分析1.分析构造函数2.分析尾插等 二、手把手教你写一个list1.结点声明2.list类的成员变量3.list类的默认构造函数4.list类的尾插5.结点的默认构造函数6.list类的迭代器7.设计const迭代器8.list的insert、erase等接口9.size10.list的clear11.list的析构函数… 文章目录 一、list源码分析1.分析构造函数2.分析尾插等 二、手把手教你写一个list1.结点声明2.list类的成员变量3.list类的默认构造函数4.list类的尾插5.结点的默认构造函数6.list类的迭代器7.设计const迭代器8.list的insert、erase等接口9.size10.list的clear11.list的析构函数12.list拷贝构造函数13.赋值运算符重载14. 测试代码 三、模拟list类的全部代码 一、list源码分析
1.分析构造函数
list的分析与vector的分析思路是一样的我们一开始最先看到的就是这个结点的结构体在这里我们可以注意到这是一个双向链表。有一个前驱指针一个后继指针。然后在有一个存储数据的空间
其次我们还会注意到它的迭代器是一个自定义类型而非原生指针。这与vector是不同的至于迭代器为什么要这么设计我们暂时还看不懂那么我们就往下继续看先把大结构给研究出来
那么我们继续找成员变量在这里我们就找到了成员变量但是这个类型我们很明显看不懂于是我们速览定义去查看
可以看到这个实际上还是一个指针。但是这个指针我们还是看不懂于是我们继续去速览定义于是就找到了这里
这里我们可以注意到这个结点的类型其实就是一个类模板这个模板正好就是我们一开始就看到的用结构体定义的一个结点。于是我们就清楚了这个成员变量实际就是一个指针这个指针指向一个结点。这样一想象就有点类似于我们在c语言使用链表时候的头节点了。
那么接下来我们应该分析一下构造函数是什么样子的。 不难注意到就在成员变量的下方正好就是一个无参的构造函数。也就是默认构造函数
但是在这里它又封装了一层函数于是乎我们继续深入查看
如下所示我们看到了具体的函数内容从名字上来看get_node 不出意外就是开空间的。也就是得到一个结点然后返回这个结点指针。这样一来我们的成员变量就获取的实际的一个结点然后让它的next和prev都指向自己这样一来这个结点形成一个自循环。现在就能看出来这是一个带头双向循环链表了
那么这个得到结点的函数内部究竟是什么我们还可以继续深入查看一下
如上图所示这里的allocated设计到空间配置器。这里我们就先不做了解了。后序在详细介绍
我们不妨顺着这个思路往下继续理解下面刚好有一个put_node这个函数其实就是释放结点的。
在后面还有这样一个函数这个函数是creat_node不难理解这个就是获取一个结点先给这个结点开空间然后调用构造函数。等一系列操作。
既然这里涉及到一个构造那么我们继续深入看看这个构造里面是什么东西这里其实我们还是有点懵的这里其实就涉及到了C11的内容了我们就先不管它了我们只需要这道能new出来空间就行了
2.分析尾插等
好了构造函数分析完了那么我们继续分析一下push_back系列的插入函数
我们不难注意到这里的push_front和push_back都是复用了insert接口那么我们就直接去分析一下insert接口吧
我们可以分析出来它调用的是这个函数 在这里我们也是不难理解的先创造一个结点然后进行连接。现在我们也基本读懂了这个大体的框架了
这里还需要注意的是由于一开始的结点里面的指针都是空指针导致后面需要经历很多的强制类型转化。其实这里大可不必我们如果一开始就定义好指针的类型自然是最好的。
二、手把手教你写一个list
1.结点声明
如下所示是我们的结点的定义对于这里的定义我们可能刚看到的时候会比较陌生感又有一丝熟悉感这是正常的。多写写就熟悉了。我们现在来深入了解一下这个结点是如何进行声明的我们这里和c语言的链表采用同样的方法使用一个结构体但是这里的结构体已经非比结构体了。因为C对结构体进行了升级这里应该是一个类使用struct的话会是类成员变量默认为公有的成员变量方便类外的变量可以随时访问。
其次C中对结点进行定义的时候可以只写类名这与class是一样的。注意不要忘记带上模板参数T因为我们写的结点也只是一个模板。因为类名不是类型他实例化以后可以有各种各样的结点类型。 templateclass Tstruct list_node{list_nodeT* _next;list_nodeT* _prev;T _val;};2.list类的成员变量
由于我们的结点是一个模板对于它而言它的类型就比较繁琐我们可以在list类里面使用typedef进行一次重命名。然后再私有里面再定义一个指针这个指针就是一个结点指针。 templateclass Tclass list{typedef list_nodeT Node;public:private:Node* _head;};3.list类的默认构造函数
如下所示我们定义好了成员变量以后我们就写一个默认构造函数当我们对这个链表类进行实例化的时候自动调用这个默认构造函数这个默认构造函数会为成员变量的头节点指针分配实际的空间在new Node空间的时候会调用它Node即list_nodeT类的默认构造函数函数。从而成功的开辟好这块空间。 list(){_head new Node;_head-_next _head;_head-_prev _head;}4.list类的尾插
如下所示我们的尾插逻辑也是比较简单的先利用我们传过来的val去开辟一个新的结点注意这里开辟新结点的时候使用new的话可以直接带一个括号去调用它的构造函数 void push_back(const T val){Node* newnode new Node(val);Node* tail _head-_prev;tail-_next newnode;newnode-_prev tail;newnode-_next _head;_head-_prev newnode;}5.结点的默认构造函数
有了上面的分析之后我们现在缺的就是一个结点的默认构造函数我们直接给一个缺省值使用T()就是一个匿名对象来初始化对于内置类型也是同样适用的。然后我们使用初始化列表即可。 list_node(const T val T()):_next(nullptr),_prev(nullptr),_val(val){}6.list类的迭代器
首先我们思考一下可否像vector一样直接在类里面typedef 一个迭代器
答案是显然不可以的这样大错特错。vector可以这样使用的原因是数组天生就是一个迭代器。解引用后就能找到对应的值。
而对于list首先它就是不连续的指针加1后地址早已不知道跑到哪个结点去了。其次这里仅仅只是结点的指针解引用后找到的仅仅只是结点我们还需要进一步解引用才能找到对应的真正的值。 总之直接typedef的话会使得迭代器的和解引用操作均失效了这时候我们只能使用运算符重载了。才能解决这个问题。既然要运算符重载这里我们最好再次封装一个类出来。因为如果不封装一个类出来的话我们无法完成此处的运算符重载。
如下所示是我们实现的iterator的类 templateclass Tstruct __list_iterator{typedef list_nodeT Node;Node* _node;__list_iterator(Node* node):_node(node){}T operator*(){return _node-_val;}__list_iteratorT operator(){_node _node-_next;return *this;}bool operator!(const __list_iteratorT it){return _node ! it._node;}};这个类我们使用了一个结构体去封装在这个结构体中我们只有一个成员变量这个成员变量是结点类的指针用于指向某一个结点 在我们一开始定义出迭代器的时候我们需要先写一个构造函数用于迭代器的初始化。即需要传一个参数node来控制。
与之对应的我们在list中就需要写出对应的begin和end函数来返回迭代器。 typedef __list_iteratorT iterator;iterator begin(){//return _head-_next //单参数的构造函数支持隐式类型转换return iterator(_head-_next);}iterator end(){return iterator(_head);}
在这里的迭代器中首先返回值肯定是iterator根据我们前面iterator函数的构造函数我们可以利用匿名对象去构造一个迭代器对象。这里我们正好传一个参数这个参数根据我们函数的特性去传递在list类中它的成员变量就是一个结点类指针我们可以直接传递该节点的下一个指针用这个指针刚好就能构造出这个迭代器类型。
现在我们已经获得了这个迭代器这个迭代器本质就是一个类而不是指针。由于结点是无法直接正常解引用的那么我们就需要去在迭代器类中去重载一个*运算符让他看上去就像一个指针一样试想一下我们解引用出来的结果应该是什么呢其实就是该迭代器类型里面这个唯一的公有成员变量_node所指向的结点中的_val这个_val就是我们所需要返回的值。这个值的类型是T由于解引用后我们还可以去修改这个结点里面的值所以我们还需要传引用返回
除此之外我们还需要一个运算符重载在这个运算符重载中我们也很明确我们需要返回的类型就是迭代器类型。那么我们是如何进行的呢因为我们的成员变量就是指向一个结点的指针所以我们直接让这个结点的指针去往后移动一次即可。由于是前置所以我们先移动在返回*this因为*this就是我们的该迭代器。这里我们注意我们可以传引用返回也可以传值返回。因为无非就是多了一个类。如果传引用返回另外一个类改变的时候这个it所指向的内容也将改变。如果传值返回就不会了。
为了方便我们测试我们还需要再写一个的运算符重载这个运算符重载我们在上面也给出来了就是简单的进行比较即可。
我们使用如下代码进行测试这里的测试代码与list在同一个命名空间所以不需要域作用限定符 void test1(){listint lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);listint::iterator it lt.begin();while (it ! lt.end()){cout *it ;it;}cout endl;}总而言之list的迭代器确实比较抽象一些这里存在三个类之间的各种纠缠。所以导致比较抽象但是认真分析之后还是比较容易读懂的。
那么我们再来思考一下这里是否需要拷贝构造呢事实上这里我们可以不需要写拷贝构造函数因为库里面会默认生成一个浅拷贝而我们这里也就需要一个浅拷贝。不需要深拷贝。所以我们不需要写。
那么我们在思考一下我们这里有很多个迭代器迭代器里面的指针指向同一块空间那么这里是否会产生崩溃呢其实是不会的因为我们就没写析构函数。那么为什么不写析构呢其实这是因为这个结点就不是我这个迭代器去生成的迭代器只是拿走了这个结点的地址罢了。要析构也轮不到迭代器去析构应该让list去析构。迭代器只是借助这个结点去访问容器。迭代器只是为了访问而不是去管理容器。
我们这里先将迭代器的基本操作写的稍微完善一些 templateclass Tstruct __list_iterator{typedef list_nodeT Node;Node* _node;__list_iterator(Node* node):_node(node){}T operator*(){return _node-_val;}__list_iteratorT operator(){_node _node-_next;return *this;}__list_iteratorT operator(int){__list_iteratorT tmp(*this);_node _node-_next;return tmp;}bool operator!(const __list_iteratorT it){return _node ! it._node;}bool operator(const __list_iteratorT it){return _node it._node;}};7.设计const迭代器
我们先来看看下面这种设计方法是否可行
先说结论不行为什么不行呢这是因为const迭代器要求的是迭代器指向的内容不可以被修改迭代器本身可以被修改。而这里呢我们的对迭代器类型加上了const我们的迭代器本身就是一个类对一个类加上一个const这是让这个类对象无法被修改啊。里面的成员变量都不可以被修改而我们迭代器对象里面的指针指向的才是结点指针。我们这样一来这个迭代器里面的指针无法移动了。也就意味着不满足我们的迭代器本身可以被修改的性质了。它就无法调用前置后置了。
那么我们到底该如何控制指向的数据不可被修改呢 答案就是在这里加上const
这样一来返回的就是const引用自然就无法进行修改内容了。
这样一来我们就有了一种实现const迭代器的想法了。我们可以拷贝一份原来的迭代器然后改变一下类名和解引用这个成员函数的返回值即可 templateclass Tstruct __list_const_iterator{typedef list_nodeT Node;Node* _node;__list_const_iterator(Node* node):_node(node){}const T operator*() {return _node-_val;}__list_const_iteratorT operator() {_node _node-_next;return *this;}__list_const_iteratorT operator(int) {__list_const_iteratorT tmp(*this);_node _node-_next;return tmp;}bool operator!(const __list_const_iteratorT it) {return _node ! it._node;}bool operator(const __list_const_iteratorT it) {return _node it._node;}};即如上代码所示但是这样设计太过于冗余了。不过这个也是可以正常运行的我们先补两个接口 const_iterator begin() const{//return _head-_next //单参数的构造函数支持隐式类型转换return const_iterator(_head-_next);}const_iterator end() const{return const_iterator(_head);}如上所示代码中要特别注意的是我们访问这两个接口时候使用的是list类并且是const的对象那么一定要加上const否则就是权限放大了。
我们来测试一下const迭代器我们只需要在上面的测试用例中补上一个Print接口即可
void Print(const listint lt){listint::const_iterator it lt.begin();while (it ! lt.end()){cout (*it) ;it;}cout endl;}显然是可以的不过还是刚才那个问题这个迭代器太冗余了。因为仅仅就是一个返回值不一样而已那么我们能否去改善呢其实是可以的。我们可以通过一个类型去控制这个返回值而要控制这个类型就需要增加一个模板参数即可
我们可以这样做
在迭代器类中添加一个Ref参数
然后让*的运算符重载返回这个模板参数。 最后我们在list类中定义const_iterator的时候这样定义。
如此一来很巧妙的解决了代码冗余的问题。虽然说从实际上来说并无太大变化。本质还是两个迭代器类。但是使我们的代码更加精简了 不过这样一来虽然list精简了但是按照我们之前的迭代器代码后面的大部分迭代器类型都需要大幅度改动于是我们不妨使用typedef一下。以防后序再次修改。
如下代码所示 templateclass T, class Refstruct __list_iterator{typedef list_nodeT Node;typedef __list_iteratorT, Ref self;Node* _node;__list_iterator(Node* node):_node(node){}Ref operator*(){return _node-_val;}self operator(){_node _node-_next;return *this;}self operator(int){self tmp(*this);_node _node-_next;return tmp;}bool operator!(const self it){return _node ! it._node;}bool operator(const self it){return _node it._node;}};当然现在还没完还有时候我们可能会写出这样的代码 struct A{A(int a 0, int b 0):_a(a),_b(b){}int _a;int _b;};void test2(){listA lt;lt.push_back(A(1, 1));lt.push_back(A(2, 2));lt.push_back(A(3, 3));lt.push_back(A(4, 4));lt.push_back(A(5, 5));listA::iterator it lt.begin();while (it ! lt.end()){cout it-_a ;it;}cout endl;}在这里我们显然发现是无法正常运行的。由于迭代器是类似于指针的操作我们有时候就需要-操作符去解引用。所以我们就需要写一个-的运算符重载。 T* operator-(){return _node-_val;}如上所示是写在迭代器里面的operator运算符重载。
利用这个运算符重载我们就可以跑上面的代码了
然而当我们细心的话我们会发现这个运算符重载是比较怪异的。哪里怪异呢
首先我们这个运算符重载返回的是什么呢是A*也就是说它还需要一次-解引用才能找到真正的值。那么我们这里为什么可行呢
严格来说it--_a才是符合语法的。 因为运算符重载要求可读性那么编译器特殊处理省略了一个-
上面这个运算符重载仅仅只是针对于普通对象的如果是const对象的话那么我们只能使用跟*运算符重载一样的处理方法多传一个参数才可以解决这个问题。也就是我们需要三个模板参数才可以。 最终我们的迭代器代码如下所示 templateclass T, class Ref, class Ptrstruct __list_iterator{typedef list_nodeT Node;typedef __list_iteratorT, Ref, Ptr self;Node* _node;__list_iterator(Node* node):_node(node){}Ref operator*(){return _node-_val;}Ptr operator-(){return _node-_val;}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;}bool operator!(const self it) const{return _node ! it._node;}bool operator(const self it) const{return _node it._node;}};8.list的insert、erase等接口
当我们实现了迭代器以后剩余的接口其实就很简单了与C语言中list的实现是一模一样的。 void push_back(const T val){//insert(end(), val);Node* newnode new Node(val);Node* tail _head-_prev;tail-_next newnode;newnode-_prev tail;newnode-_next _head;_head-_prev newnode;}void push_front(const T val){insert(begin(), val);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T val){Node* newnode new Node(val);Node* cur pos._node;Node* prev cur-_prev;prev-_next newnode;newnode-_prev prev;newnode-_next cur;cur-_prev newnode;return newnode;}iterator erase(iterator pos){assert(pos ! end());Node* cur pos._node;Node* prev cur-_prev;Node* next cur-_next;delete cur;cur nullptr;prev-_next next;next-_prev prev;return next;}9.size
对于这个size我们有两种方法第一种如下所示我们直接遍历统计。这样时间复杂度是O(N) size_t size(){size_t sz 0;iterator it begin();while (it ! end()){it;sz;}return sz;}还有一种方法是增加一个私有成员变量_size当插入数据的时候加一当删除数据的时候减一即可。还有构造函数我们也需要初始化一下这个_size。
这样一来我们只需要将前面的代码都给修改一下即可。
10.list的clear
对于clear我们直接复用前面的接口即可。 void clear(){iterator it begin();while (it ! end()){it erase(it);}}11.list的析构函数
析构函数也是很简单的析构和clear的区别就是析构会删除头节点而clear不会删除头节点。 ~list(){clear();delete _head;_head nullptr;}12.list拷贝构造函数
我们这里已经涉及到资源的申请与释放了所以我们必须得构造一个深拷贝构造函数 list(const listT lt){_head new Node;_head-_next _head;_head-_prev _head;_size 0;for (auto e : lt){push_back(e);}}当然在这里我们可能会觉得拷贝构造和默认构造有点重复了。我们可以对前面重复的部分在封装一个函数从而简化代码 void empty_init(){_head new Node;_head-_next _head;_head-_prev _head;_size 0;}list(){//_head new Node;//_head-_next _head;//_head-_prev _head;//_size 0;empty_init();}list(const listT lt){//_head new Node;//_head-_next _head;//_head-_prev _head;//_size 0;empty_init();for (auto e : lt){push_back(e);}}13.赋值运算符重载
如下所示这个也是比较简单我们直接使用现代写法即可 void swap(listT lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}listT operator(listT lt){swap(lt);return *this;}这里我们还有一个东西需要注意的是 我们也许会发现库里面的函数返回值和形参写的是类名而不是类型
这个的话是因为在类模板里面写成员函数的时候是允许用类名代替类型的。
即我们的代码下面这些部分可以直接换为类名但是呢这里不建议使用因为会降低可读性。
14. 测试代码
我们现在用如下的代码可以测试出以上的全部函数的使用 void test3(){listint lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);listint::iterator it lt.begin();while (it ! lt.end()){cout *it ;it;}cout endl;lt.push_front(6);lt.push_front(7);lt.push_front(8);lt.push_front(9);lt.push_front(10);for (auto e : lt){cout e ;}cout endl;Print(lt);cout lt.size() endl;lt.clear();cout lt.size() endl;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);it lt.begin();it;for (auto e : lt){cout e ;}cout endl;it lt.insert(it, 100);for (auto e : lt){cout e ;}cout endl;it--;it lt.insert(it, 200);for (auto e : lt){cout e ;}cout endl;it;it lt.insert(it, 300);for (auto e : lt){cout e ;}cout endl;--it;it lt.erase(it);for (auto e : lt){cout e ;}cout endl;lt.pop_back();lt.pop_front();for (auto e : lt){cout e ;}cout endl;listint lt2;lt2.push_back(1);lt2 lt;for (auto e : lt2){cout e ;}cout endl;}经测试运行结果正常
三、模拟list类的全部代码
#define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
#includelist
#includeassert.husing namespace std;namespace Sim
{templateclass Tstruct list_node{list_nodeT* _next;list_nodeT* _prev;T _val;list_node(const T val T()):_next(nullptr),_prev(nullptr),_val(val){}};templateclass T, class Ref, class Ptrstruct __list_iterator{typedef list_nodeT Node;typedef __list_iteratorT, Ref, Ptr self;Node* _node;__list_iterator(Node* node):_node(node){}Ref operator*(){return _node-_val;}Ptr operator-(){return _node-_val;}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;}bool operator!(const self it) const{return _node ! it._node;}bool operator(const self it) const{return _node it._node;}};//templateclass T//struct __list_const_iterator//{// typedef list_nodeT Node;// Node* _node;// __list_const_iterator(Node* node)// :_node(node)// {}// const T operator*() // {// return _node-_val;// }// __list_const_iteratorT operator() // {// _node _node-_next;// return *this;// }// __list_const_iteratorT operator(int) // {// __list_const_iteratorT tmp(*this);// _node _node-_next;// return tmp;// }// bool operator!(const __list_const_iteratorT it) // {// return _node ! it._node;// }// bool operator(const __list_const_iteratorT it) // {// return _node it._node;// }//};templateclass Tclass list{typedef list_nodeT Node;public:typedef __list_iteratorT, T, T* iterator;//typedef __list_const_iteratorT const_iterator;typedef __list_iteratorT, const T, const T* const_iterator;iterator begin(){//return _head-_next //单参数的构造函数支持隐式类型转换return iterator(_head-_next);}iterator end(){return iterator(_head);}const_iterator begin() const{//return _head-_next //单参数的构造函数支持隐式类型转换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;_size 0;}list(){//_head new Node;//_head-_next _head;//_head-_prev _head;//_size 0;empty_init();}list(const listT lt){//_head new Node;//_head-_next _head;//_head-_prev _head;//_size 0;empty_init();for (auto e : lt){push_back(e);}}void swap(listT lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}listT operator(listT lt){swap(lt);return *this;}void push_back(const T val){insert(end(), val);//Node* newnode new Node(val);//Node* tail _head-_prev;//tail-_next newnode;//newnode-_prev tail;//newnode-_next _head;//_head-_prev newnode;}void push_front(const T val){insert(begin(), val);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T val){Node* newnode new Node(val);Node* cur pos._node;Node* prev cur-_prev;prev-_next newnode;newnode-_prev prev;newnode-_next cur;cur-_prev newnode;_size;return newnode;}iterator erase(iterator pos){assert(pos ! end());Node* cur pos._node;Node* prev cur-_prev;Node* next cur-_next;delete cur;cur nullptr;prev-_next next;next-_prev prev;--_size;return next;}size_t size(){//size_t sz 0;//iterator it begin();//while (it ! end())//{// it;// sz;//}//return sz;return _size;}~list(){clear();delete _head;_head nullptr;}void clear(){iterator it begin();while (it ! end()){it erase(it);}}private:Node* _head;size_t _size;};void Print(const listint lt){listint::const_iterator it lt.begin();while (it ! lt.end()){cout (*it) ;it;}cout endl;}void test1(){listint lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);listint::iterator it lt.begin();while (it ! lt.end()){cout *it ;it;}cout endl;for (auto e : lt){cout e ;}cout endl;Print(lt);}struct A{A(int a 0, int b 0):_a(a),_b(b){}int _a;int _b;};void Print(const listA lt){listA::const_iterator it lt.begin();while (it ! lt.end()){cout it-_a ;it;}cout endl;}void test2(){listA lt;lt.push_back(A(1, 1));lt.push_back(A(2, 2));lt.push_back(A(3, 3));lt.push_back(A(4, 4));lt.push_back(A(5, 5));cout lt.size() endl;lt.clear();cout lt.size() endl;listA::iterator it lt.begin();while (it ! lt.end()){cout it-_a ;it;}cout endl;Print(lt);}void test3(){listint lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);listint::iterator it lt.begin();while (it ! lt.end()){cout *it ;it;}cout endl;lt.push_front(6);lt.push_front(7);lt.push_front(8);lt.push_front(9);lt.push_front(10);for (auto e : lt){cout e ;}cout endl;Print(lt);cout lt.size() endl;lt.clear();cout lt.size() endl;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);it lt.begin();it;for (auto e : lt){cout e ;}cout endl;it lt.insert(it, 100);for (auto e : lt){cout e ;}cout endl;it--;it lt.insert(it, 200);for (auto e : lt){cout e ;}cout endl;it;it lt.insert(it, 300);for (auto e : lt){cout e ;}cout endl;--it;it lt.erase(it);for (auto e : lt){cout e ;}cout endl;lt.pop_back();lt.pop_front();for (auto e : lt){cout e ;}cout endl;listint lt2;lt2.push_back(1);lt2 lt;for (auto e : lt2){cout e ;}cout endl;}
} 好了本节内容就到这里了 本节内容难度稍大希望读者可以好好阅读。有不懂的可以及时私聊博主解答疑惑
如果对你有帮助的话不要忘记点赞加收藏哦