STL常用容器—list容器(链表)

STL常用容器—list容器(链表)

  • 一、list容器基本概念
  • 二、list容器基本操作与常用方法
    • 1. list构造函数
    • 2. ☆list 插入和删除
    • 3. list 获取头尾数据
    • 4. list 大小操作
    • 5. list赋值和交换
    • 6. list 反转和排序
  • 三、排序案例

参考博文1: <C++> list容器本质|常用接口|自定义排序规则
参考博文2:STL常用容器—— list 容器的使用

  本文主要整理总结C++ STL中list(链表)常用容器的常用方法的操作,关于链表的底层设计与C语言实现请参考博文:【数据结构与算法】——单链表的原理及C语言实现

一、list容器基本概念

  list 容器 的本质是一个双向循环链表,用于存储的每个结点包含数据域指针域

示意图:

名词解释:

  • beginend 都是迭代器,可以看成指针来操作
    begin 对应的是容器首个元素,而end 对应容器最后一个元素的下一个位置
  • prevnext 代表前驱指针和后继指针,并不是 list 容器的接口,指针域用来存储下一个结点的地址
  • frontback 分别是第一个和最后一个结点的数据域
  • push_backpush_frontpop_backpop_front 代表尾插、头插、尾删、头删

通过前驱后继指针可以将每个结点连接起来,头结点的前驱与尾结点后继指针都指向null
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器

list的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出
  • 可以对任意位置进行快速插入或删除元素,修改指针即可,不需要移动大量元素

list的缺点:

  • 链表灵活,但是空间(指针域)和 时间(遍历)额外耗费较大

STL中List和vector是两个最常被使用的容器,各有优缺点

二、list容器基本操作与常用方法

1. list构造函数

函数原型功能
list<T> lst;采用模板类实现,对象的默认构造形式
list<T> lst = {x1,x2...};构造并出初始化
list(n,elem);n个elem
list(const list &lst);拷贝构造函数
list(beg,end);构造函数将[beg, end)区间中的元素拷贝给本身

示例:

list<int> list1;
list1.push_back(10);
list1.push_back(20);
list1.push_back(30);list<int> list2={2,4,6,8};//构造并初始化
list<int> list3(5,100);		//5个100
list<int> list4(list1);		//拷贝list1//list2的部分区间
list<int> list5(++list2.begin(), --list2.end());		cout << "list1: ";	showList(list1);
cout << "list2: ";	showList(list2);
cout << "list3: ";	showList(list3);
cout << "list4: ";	showList(list4);
cout << "list5: ";	showList(list5);

其中showList:

void showList(list<int> &list)
{for(int item:list)cout << item  << " ";cout << endl;
}

2. ☆list 插入和删除

方法原型功能
-----------常用-----------
push_back(elem);在容器尾部插入一个元素
push_front(elem);在容器开头插入一个元素
pop_back();删除容器中最后一个元素
pop_front();删除容器中第一个元素
clear();清空容器所有数据
-----------不常用-----------
insert(pos,elem);在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);在pos位置插入[beg,end)区间的数据,无返回值
erase(beg,end);删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos);删除pos位置的数据,返回下一个数据的位置
remove(elem);删除容器中所有与elem值匹配的元素。

示例:

void test()
{list<int> list1;//尾插list1.push_back(2);	list1.push_back(4);//头插list1.push_front(10);list1.push_front(30);cout << "list1 push back + front: ";showList(list1);			//30 10 2 4//尾删list1.pop_back();cout << "pop back: ";	showList(list1);			//30 10 2//头删list1.pop_front();cout << "pop front: ";	showList(list1);			//10 2//头+1插list1.insert(++list1.begin(), 666);cout << "front insert: ";	showList(list1);			//10 666 2//头+1删list1.erase(++list1.begin());cout << "front+1 erase: ";	showList(list1);			//10  2
}

3. list 获取头尾数据

  list 容器不支持随机访问,不提供下标操作符 [] 和 at() 成员函数,也没有提供 data() 成员函数。
  只能使用 front() 和 back() 成员函数,或者使用 list 容器迭代器访问或修改元素的值。

使用 front() 和 back() 成员函数

方法原型功能
front();返回第一个元素
back();返回最后一个元素
int main()
{list<int> list1 = {2,4,6,8,10};//获取元素引用int& first = list1.front();int& last  = list1.back();cout << first << " " << last << endl;//修改元素first = 100;last  = 200;cout << list1.front() << " " << list1.back() << endl;return 0;
}

注意:

  • list容器中不可以通过[]或者at方式访问数据
  • 返回第一个元素 — front
  • 返回最后一个元素 — back

使用 list 容器迭代器

int main()
{list<int> list1 = {2,4,6,8,10};auto it = list1.begin();	//迭代器指向头while(it != list1.end())	//迭代遍历{cout << *it << " ";it++;					//迭代器自增}return 0;
}

注意: list容器的迭代器类型为双向迭代器,而不是和之前的array、vector容器一样是随机访问迭代器。

双向迭代器特性:假如it1,it2都是双向迭代器,那么:

支持:++it1、 it1++、 it1- -、 it1++、 *it1、 it1 == it2 以及 it1 != it2
不支持:it1[i]、it1-=i、 it1+=i、 it1+i 、it1-i、it1 < it2、it1 > it2、 it1 <= it2、 it1 >= it2

4. list 大小操作

方法原型功能
size(); 返回容器中元素的个数
empty(); 判断容器是否为空
resize(num);重新指定容器的长度为num,若容器变长,则以默认值0填充;若变短,则删除末尾多余元素
resize(num, elem); 重新指定容器的长度为num,若容器变长,则以 elem 填充;若变短,则删除末尾多余元素

示例程序:

void test()
{list<int> list1 = {10,20,30};list<int> list2 = {2,4,6,8,10};if(!list1.empty()){cout << "size: " << list1.size() << endl;list1.resize(5);	//重置大小为5个,以默认值填充cout << "resize: " << list1.size() << endl;showList(list1);}elsecout << "容器为空" << endl;
}

5. list赋值和交换

方法原型功能
assign(beg, end);将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem);将n个elem拷贝赋值给本身
list& operator=(const list &lst);已重载 = 操作符
swap(lst);将list与本身的元素互换

示例:

list<int> list1 = {10,20,30};
list<int> list2 = {2,4,6,8,10};list1 = list2;			
showList(list1);	//2,4,6,8,10list1.assign(5,100);	
showList(list1);	//5个100list1.assign(++list2.begin(),--list2.end());	
showList(list1);	//4,6,8list1.swap(list2);
showList(list1);	//2,4,6,8,10
showList(list2);	//4,6,8

6. list 反转和排序

方法原型功能
reverse();反转链表
sort();链表排序

示例:

//用于降序排序
bool myCompare(int v1, int v2)
{//降序:让第一个数 > 第二个数return v1 > v2;
}void test03()
{list<int> list1 = {6,4,2,10,3};cout << "src data: ";	showList(list1);//降序排序list1.sort(myCompare);cout << "sort: "; 		showList(list1);//反转list1.reverse();cout << "reverse: ";	showList(list1);
}

sortlist 容器内部的排序方法,默认为升序排列,需要通过自己编写函数(仿函数)来决定排序的规则。

三、排序案例

案例描述: 将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则: 按照年龄进行升序,如果年龄相同按照身高进行降序

示例程序:

/******************自定义Person类****************/
class Person {
public:Person(string name, int age , int height){this->name = name;this->age = age;this->height = height;}public:string name;  //姓名int age;      //年龄int height;   //身高
};
/*****************定义仿排序顺序 仿函数**************/
bool PersonCompare(Person &p1, Person &p2)
{if(p1.age == p2.age)	//年龄相同 按身高降序{if(p1.height > p2.height)return true;elsereturn false;}else	//按年龄升序{if(p1.age < p2.age)return true;elsereturn false;}		
}
/****************遍历容器函数**************/
void showPersonList(list<Person> &list)
{auto it = list.begin();for( ; it != list.end(); it++){cout << "name: " << it->name << "\tage: " << it->age;cout << "\t\theight: " << it->height << endl;}
}
/*****************主程序 测试程序*************/
void test04()
{Person p1("张三", 22, 170);Person p2("李四", 21, 173);Person p3("王五", 20, 168);Person p4("陈六", 25, 177);Person p5("赵七", 22, 180);list<Person> list1 = {p1,p2,p3,p4,p5};//排序前cout << "before sort: " << endl; showPersonList(list1);//自定义排序list1.sort(PersonCompare);//显示排序后结果cout << "after sort: " << endl; showPersonList(list1);
}

程序输出:

总结:

  • 对于自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序
  • 高级排序只是在排序规则上再进行一次逻辑规则制定,并不复杂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/666354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉中的目标跟踪

从保护我们城市的监控系统到自动驾驶车辆在道路上行驶&#xff0c;目标跟踪已经成为计算机视觉中的一项基础技术。本文深入探讨了目标跟踪&#xff0c;探索了其基本原理、多样化的方法以及在现实世界中的应用。 什么是目标跟踪&#xff1f; 目标跟踪是深度学习在计算机视觉中广…

JAVA Web 学习(四)RabbitMQ、Zookeeper

十、消息队列服务器——RabbitMQ RabbitMQ是使用Erlang语言开发的开源消息队列系统&#xff0c;基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全。AMQP协议更多用在企业系统内&#xff0c;对数据一致性、稳定性和可靠性要求…

ES6-let

一、基本语法 ES6 中的 let 关键字用于声明变量&#xff0c;并且具有块级作用域。 - 语法&#xff1a;let 标识符;let 标识符初始值; - 规则&#xff1a;1.不能重复声明let不允许在相同作用域内重复声明同一个变量2.不存在变量提升在同一作用域内&#xff0c;必须先声明才能试…

JS(react)图片压缩+图片上传

上传dome var fileNodeTakeStock: any createRef();<inputref{fileNodeTakeStock}onChange{showPictureTakeStock}style{{ display: "none" }}id"fileInpBtn"type"file"accept"image/*" //限制上传格式multiple{false}capture&qu…

RK Camera hal 图像处理

soc&#xff1a;RK3568 system:Android12 今天发现外接的USBCamera用Camera 2API打开显示颠倒&#xff0c;如果在APP 里使用Camera1处理这块接口较少&#xff0c;调整起来比较麻烦 RK Camera hal位置&#xff1a;hardware/interfaces/camera 核心的文件在&#xff1a; 开机…

深入理解Istio服务网格(一)数据平面Envoy

一、服务网格概述(service mesh) 在传统的微服务架构中&#xff0c;服务间的调用&#xff0c;业务代码需要考虑认证、熔断、服务发现等非业务能力&#xff0c;在某种程度上&#xff0c;表现出了一定的耦合性 服务网格追求高级别的服务流量治理能力&#xff0c;认证、熔断、服…

N-142基于springboot,vue停车场管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plus 本项目分为普通用户和管理员…

基于若依的ruoyi-nbcio流程管理系统自定义业务回写状态的一种新方法(一)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

深度学习驱动下的自然语言处理进展及其应用前景

文章目录 每日一句正能量前言技术进步应用场景挑战与前景自然语言处理技术当前面临的挑战未来的发展趋势和前景 伦理和社会影响实践经验后记 每日一句正能量 一个人若想拥有聪明才智&#xff0c;便需要不断地学习积累。 前言 自然语言处理&#xff08;NLP&#xff09;是一项正…

FreeRTOS动态 / 静态创建和删除任务

本篇文章记录我学习FreeRTOS的动态 / 静态创建和删除任务的知识。希望我的分享能给你带来不一样的收获&#xff01;文中涉及FreeRTOS创建和删除任务的API函数&#xff0c;建议读者参考以下文章&#xff1a; FreeRTOS任务相关的API函数-CSDN博客 目录 ​编辑 一、FreeRTOS动态创…

“超越摩尔定律”,存内计算走在爆发的边缘

目录 ​编辑 前言 在后摩尔时代提高计算机性能 六类存内计算技术 1&#xff09;XYZ-CIM 2&#xff09;XZ-CIM 3&#xff09;Z-CIM 4&#xff09;XY-CIM 5&#xff09;X-CIM 6&#xff09;O-CIM 各种CIM技术的原理 1&#xff09;XYZ-CIM&#xff1a;NVM有状态逻辑 2…

ES6-数组的解构赋值

一、数组的解构赋值的规律 - 只要等号两边的模式相同&#xff0c;左边的变量就会被赋予对应的值二、数组的解构赋值的例子讲解 1&#xff09;简单的示例&#xff08;完整的解构赋值&#xff09; 示例 //基本的模式匹配 // a&#xff0c;b,c依次和1&#xff0c;2&#xff0c…

【C生万物】初始C语言

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

【微服务】skywalking自定义链路追踪与日志采集

目录 一、前言 二、自定义链路追踪简介 2.1 自定义链路追踪应用场景 2.2 链路追踪几个关键概念 三、skywalking 自定义链路追踪实现 3.1 环境准备 3.2 集成过程 3.2.1 导入核心依赖 3.2.2 几个常用注解 3.2.3 方法集成 3.2.4 上报追踪信息 四、skywalking 自定义日志…

如何从 iPhone 上恢复永久删除的照片

您的 iPhone 上缺少照片吗&#xff1f;讽刺的是&#xff0c;iPhone 的许多高级功能可能正是这个问题如此普遍的原因。幸运的是&#xff0c;还有很多方法可以从 iPhone 恢复已删除的照片&#xff0c;具体取决于您设备的设置方式。 本文涵盖了所有这些内容。该过程根据您的具体情…

微信公众号迁移公证书怎么办?

公众号迁移有什么作用&#xff1f;只能变更主体吗&#xff1f;公众号迁移的作用可不止是变更主体哦&#xff01;还可以把原公众号的粉丝、文章素材、违规记录、留言功能、名称等迁移到新的公众号上。这样一来&#xff0c;你就可以实现公众号的公司主体变更、粉丝转移、开通留言…

使用maven对springboot项目进行瘦身分离jar的多种处理方案

文章目录 前言一、方案一&#xff08;修改自带的spring-boot-maven-plugin插件&#xff09;二、方案二&#xff08;使用spring-boot-thin-maven-plugin插件&#xff09;总结 前言 springboot项目打包一般我们都使用它自带的spring-boot-maven-plugin插件&#xff0c;这个插件默…

大数据本地环境搭建03-Spark搭建

需要提前部署好 Zookeeper/Hadoop/Hive 环境 1 Local模式 1.1 上传压缩包 下载链接 链接&#xff1a;https://pan.baidu.com/s/1rLq39ddxh7np7JKiuRAhDA?pwde20h 提取码&#xff1a;e20h 将spark-3.1.2-bin-hadoop3.2.tar.gz压缩包到node1下的/export/server目录 1.2 解压压…

两个重要极限【高数笔记】

【第一个&#xff1a;lim &#xff08;sinx / x&#xff09; 1, x -- > 0】 1.本质&#xff1a; lim &#xff08;sin‘&#xff1f;’ / ‘&#xff1f;’&#xff09; 1, ‘&#xff1f;’ -- > 0&#xff1b;保证‘&#xff1f;’ -- > 0,与趋向无关 2.例题&#x…