当前位置: 首页 > news >正文

STL库——list(类函数学习)

ʕ • ᴥ • ʔ

づ♡ど

 🎉 欢迎点赞支持🎉

个人主页:励志不掉头发的内向程序员;

专栏主页:C++语言;


文章目录

前言

一、标准库中的list类

二、list的成员函数

2.1、构造函数

2.2、析构函数

2.3、赋值重载

2.4、运算符重载

2.5、插入和删除函数

2.5.1、push_front/pop_front函数

2.5.2、push_back/pop_back函数

2.5.3、insert/erase函数

2.6、其他成员函数

2.6.1、迭代器

2.6.2、merge函数

2.6.3、unique函数

2.6.4、remove函数

2.6.5、splice函数

三、流输入/输出

总结


前言

在学习完vector过后我们就会发现它和string相比成员函数简化了非常多,学起来也不想string那样困难,这一章节我们学习的list类时我们就会发现它的成员函数和vector相比十分相像,没有多少不同,这就是STL库的魅力所在,我们一起来看看吧


一、标准库中的list类

我们观看STL库就会发现我们vector有的成员函数我们list基本上也有,这些不同容器之间的区别在于底层的不同,但是STL库封装起来我们的上层基本上没有什么区别。

我们可以看到vector的成员函数和list是十分相像的。

二、list的成员函数

我们list类都保存在我们list的头文件中

#include <list>

2.1、构造函数

list构造也分为4种,无参构造、带参构造、迭代器区间构造以及拷贝构造

int main()
{// 无参构造list<int> a;// 带参构造,也就是用4(n)个0(val)构造blist<int> b(4, 0);// 迭代器区间构造vector<int> c({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });list<int> d(c.begin() + 1 , c.end() - 4);// 拷贝构造list<int> e(d);return 0;
}

我们可以看到和我们vector的构造函数是一样的。但是与vector不同的是list不支持下标+[]访问我们任意一个元素了,因为list想要支持得从前往后遍历,成本很高。所以想要遍历可以用迭代器和范围for。

2.2、析构函数

系统自动调用,我们不用关心。

2.3、赋值重载

赋值重载也很简单。

int main()
{list<int> a;list<int> b;a.push_back(1);a.push_back(2);a.push_back(3);a.push_back(4);// 赋值重载b = a;cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;cout << "b: ";for (auto x : b){cout << x << " ";}cout << endl;return 0;
}

2.4、运算符重载

我们的比较运算符大致规则就和vector一样,这里就不过多赘述了。

2.5、插入和删除函数

2.5.1、push_front/pop_front函数

这两个函数就是头插和头删,因为list的特殊结构,导致它的头删和头插都很容易。

int main()
{list<int> a(2, 0);a.push_front(1);a.push_front(2);a.push_front(3);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;a.pop_front();a.pop_front();a.pop_front();cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

2.5.2、push_back/pop_back函数

尾插和尾删也很容易,就不多说了。

int main()
{list<int> a(2, 0);a.push_back(1);a.push_back(2);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;a.pop_back();a.pop_back();cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

2.5.3、insert/erase函数

这两个函数和vector一样是依靠我们迭代器去插入和删除的。

但是和vector不同之处在于list的迭代器不能进行+/-,如果想要插入或者删除第3个位置的元素,不能直接begin+3或者end-*,只能用一个循环先去改变迭代器位置再去插入或者删除。

int main()
{list<int> a({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });list<int>::iterator it = a.begin();int k = 3;while (k--){it++;}a.erase(it);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

这使得本来使用率不高的两个函数在list中更低了。

2.6、其他成员函数

2.6.1、迭代器

我们迭代器和原来的用法差不多,比如来个循环遍历list。

int main()
{list<int> a;list<int> b;a.push_back(1);a.push_back(2);a.push_back(3);a.push_back(4);list<int>::iterator it = a.begin();cout << "a: ";while(it != a.end()){cout << *it << " ";it++;}cout << endl;return 0;
}

可以很成功的答应出来,但是这个迭代器和vector还是有区别的,比如它不支持加减。

vector迭代器erase:

int main()
{vector<int> a({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });a.erase(a.begin() + 5);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

很成功的给删掉了。

list迭代器erase:

int main()
{list<int> a({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });a.erase(a.begin() + 5);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

直接就运行失败了。

这是因为我们链表的迭代器不是原生指针了,它底层的物理空间不是连续的。

我们之前从功能上划分把迭代器分为:

  • iterator
  • const_iterator
  • reverse_iterator
  • const_reverse_iterator

但是迭代器其实还可以从性质方面进行划分:

  • 单向迭代器
  • 双向迭代器
  • 随机迭代器

我们vector/string/deque就是经典的随机迭代器,这种迭代器特点就是除了支持++/--外还支持+/-。而我们list/map/set就是经典的双向迭代器,这种迭代器只支持++/--,不支持+/-。而单向迭代器有forwad_list/unordered_map/unordered_set,这种比双向迭代器支持的还少,只支持++,连--都不支持。它们的性质是由它们底层来决定的。

2.6.2、merge函数

这个函数的作用就是合并我们的链表。

当然它有一个前提条件就是这两个链表必须是有序的。

int main()
{list<double> a({ 1.1, 2.2, 3.3, 4.4 });list<double> b({ 0.9, 2.1, 3.2, 4.3 });a.merge(b);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;cout << "b: ";for (auto x : b){cout << x << " ";}cout << endl;return 0;
}

如果不是有序的就会报错。

2.6.3、unique函数

这个函数的主要作用就是去重,它会把list中相同的元素删掉一个,只保留一个,用法和merge相似,list必须有序,不然程序就会失效。

int main()
{list<int> a({ 1, 2, 2, 3, 4, 4, 5 });cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;a.unique();cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

无序的话:

2.6.4、remove函数

这个函数的作用就是删除一个值,它和erase很像,但是erase是给一个迭代器,而这个是给一个元素,它先是去查找这个元素在不在list中,在就把它删除,不在就不动。

int main()
{list<int> a({ 1, 2, 2, 5, 4, 4, 5 });cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;a.remove(2);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;return 0;
}

2.6.5、splice函数

这个函数的作用是把一个list中的数据转移到另外一个list中去,转移的位置是在position之前。

int main()
{list<int> a({ 1, 2, 3, 4, 5, 6, 7, 8, 9 });list<int> b({ 10, 20, 30, 40 });list<int>::iterator it = a.begin();it++;// 相当于是吧b的数据转移到a的it位置之前a.splice(it, b);cout << "a: ";for (auto x : a){cout << x << " ";}cout << endl;cout << "b: ";for (auto x : b){cout << x << " ";}cout << endl;return 0;
}

其他的像empty、clear、size之类的就不过多说明了,用法和作用vector一样。

三、流输入/输出

list没有对流输入和输出进行重载,原因可能是不方便,而且没有必要,我们就老老实实自己做就好了。


总结

以上便是我们list常用的成员函数啦。对比起string,我们现在应该很容易就能接受这些内容,这就是STL库封装的好处,下节课就是list的模拟实现了,大家下一章节再见。

🎇坚持到这里已经很厉害啦,辛苦啦🎇

ʕ • ᴥ • ʔ

づ♡ど

http://www.xdnf.cn/news/1382149.html

相关文章:

  • 财务数据报销画像技术实现:从数据采集到智能决策的全流程解析
  • 【AI自动化】VSCode+Playwright+codegen+nodejs自动化脚本生成
  • 当new一块内存时,操作系统做了哪些事情
  • 软考 系统架构设计师系列知识点之杂项集萃(134)
  • leetcode算法刷题的第二十天
  • 鸿蒙OS与Rust整合开发流程
  • 面试tips--JVM(3)--类加载过程
  • 动态加载和异步调用tasklet/workqueue day63 ay64
  • 中国剩余定理(以及扩展..)
  • .Net Core Web 架构(管道机制)的底层实现
  • [光学原理与应用-321]:皮秒深紫外激光器产品不同阶段使用的工具软件、对应的输出文件
  • 【黑客技术零基础入门】2025最新黑客工具软件大全,零基础入门到精通,收藏这篇就够了!
  • JAVA全栈Redis篇————List常用命令讲解
  • 【架构师干货】软件工程
  • Linux学习-TCP并发服务器构建(epoll)
  • Cesium 入门教程(十一):Camera相机功能展示
  • Burp系列【密码暴力破解+令牌token破解】
  • 深度学习篇---VGGNet网络结构
  • DeepInteraction++基于多模态交互的自动驾驶感知与规划框架
  • 【iOS】Masnory自动布局的简单学习
  • Linux(二) | 文件基本属性与链接扩展
  • Spring Security 深度学习(二): 自定义认证机制与用户管理
  • npm install --global @dcloudio/uni-cli 时安装失败
  • 一天认识一个神经网络之--CNN卷积神经网络
  • QT之双缓冲 (QMutex/QWaitCondition)——读写分离
  • LINUX ---网络编程(三)
  • 如何通过docker进行本地部署?
  • 机器学习回顾(二)——KNN算法
  • Day16_【机器学习概述】
  • 设计模式:组合模式(Composite Pattern)