C++——STL容器之list链表的讲解

news2024/11/17 13:31:55

目录

一.list的介绍

二.list类成员函数的讲解

        2.2迭代器

三.添加删除数据:

        3.1添加:

        3.2删除数据

 四.排序及去重函数:

错误案例如下:

方法如下:


一.list的介绍

        list列表是序列容器,允许在序列内的任何位置执行插入元素或者删除元素等操作。list列表容器的底层是由链表封装而成,并且该链表的类型还是带头双向循环链表。

二.list类成员函数的讲解

        对于list容器的成员函数们, 它们与vector与String容器的功能作用相差不大,都是增删查改,能够通过迭代器遍历或者修改容器中某个元素的数据。由于前者与后两者底层类型的不同,侧面表现出了list容器的使用是即插即用, 不需要扩容缩容,意味着不会有reserve()、shrink_to_fit()等函数,

       

        2.2迭代器

        list链表容器的迭代器与String和Vector的迭代器也不同,后两者是使用的原生指针,由于连续地址空间的缘故,指针只需要通过增加或者减少类型的字节,便可以定位到具体的位置。

        而对于List容器而言,它的元素是一个接一个的节点,每个节点是由指针相连,所以各个节点的地址并不是连续的,那么使用原生指针去寻找元素位置会相当复杂,所以list的迭代器是一种新型迭代器,采用自定义类型制造而出。

        虽说list迭代器的底层与string,vector的迭代器并不同,但是使用方式都一样:

vector<T>:: iterator vt=v.begin();

String:: iterator st=s.begin();

list<T>::iterator lt=l.begin();

都是通过类域加作用域限定符 iterator的方式去定义。 

         在迭代器中,也是分为普通迭代器、const迭代器、反向迭代器、const反向迭代器。其各个成员作用也与之前讲String、vector容器一样,这里就不再过多讲解了。不清楚的话可以翻一翻我之前写的String和vector容器的讲解.

 这里直接上练习代码:

#include<iostream>
#include<list>
int main(){
    list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	for (auto& e:l1) {
		cout << e << " ";
	}
	cout << endl;

    list<int>::iterator lit1 = l1.begin();
	while (lit1 != l1.end()) {
		cout << ++(*lit1) << " ";
		++lit1;
	}
	cout << endl;

	cout << "--------------------------------------------" << endl;

	//反向迭代器
	list<int>::reverse_iterator lit2 = l1.rbegin();
	while (lit2 != l1.rend()) {
		cout << ++(*lit2) << " ";
		++lit2;
	}
	cout << endl;

    //const反向迭代器
    list<int>::const_reverse_iterator lit3 = l1.crbegin();
    while (lit3!= l1.crend()) {
	    cout << (*lit3) << " ";
	    //cout << ++(*lit3) << " ";			//报错
	    ++lit3;
    }
    cout << endl;

    //const正向迭代器
    list<int>::const_iterator lit4 = l1.cbegin();
    while (lit4 != l1.cend()) {
    	//cout << ++(*lit3) << " ";			//报错
    	cout << (*lit4) << " ";
	    ++lit4;
    }
    cout << endl;
    }
        return 0;
    }

运行结果: 

 

 

 

三.添加删除数据:

        3.1添加:

int main(){
    list<double> l2;
	//尾插
	l2.push_back(9.25);
	l2.push_back(60.10);
	l2.push_back(32.19);
	l2.push_back(58.79);
	//头插
	l2.insert(l2.begin(), 3.14);
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//尾插
	l2.insert(l2.end(),999.99);
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//中间插
	//find是std库函数中的
	auto pos = find(l2.begin(), l2.end(), 32.19);
	l2.insert(pos, 46.99);
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//头插push_front
	l2.push_front(12.66);
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;
    return 0;
    }

 

 

        注:对于insert来说,它的形参需要指定指针类型的pos位置,而pos位置需要自己去定位链表,上图代码中我是通过库函数find去进行定位的,list容器本身并不会提供find函数,因为库中的find函数形参以及返回值就可以很好的帮助我们进行定位。

并且之前我讲过vector容器中,insert函数会引发指针失效问题,在list中,insert函数不会引发该问题。

 

 

 

        3.2删除数据

    list<char> l2;
	l2.push_back('a');
	l2.push_back('b');
	l2.push_back('c');
	l2.push_back('d');

	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//尾删
	l2.pop_back();
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//头删
	l2.pop_front();
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//中间删——erase
	l2.push_back('h');
	l2.push_back('i');
	l2.push_back('j');
	l2.push_back('k');
	
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

	//find是std库函数中的
	auto pos = find(l2.begin(), l2.end(), 'p');
		//l2.erase(pos);		//找不到的删会报异常
	for (auto& e : l2) {
	cout << e << "  ";
	}
	cout << endl;

	 pos = find(l2.begin(), l2.end(), 'h');
	l2.erase(pos);
	for (auto& e : l2) {
		cout << e << "  ";
	}
	cout << endl;

运行结果: 

 

 

 四.排序及去重函数:

 

void Test6() {
	list<int> l1;
	l1.push_back(34);
	l1.push_back(100);
	l1.push_back(26);
	l1.push_back(79);
	l1.push_back(83);
	l1.push_back(0);
	l1.push_back(34);
	l1.push_back(55);
	l1.push_back(13);
	for (auto& e : l1) {
		cout << e << " ";
	}
	cout << endl;

	//排序
	l1.sort();
	for (auto& e : l1) {
		cout << e << " ";
	}
	cout << endl;

    }

 

 sort()函数可对list对象的元素进行整体排序。

        去重就是对该链表对象进行遍历,将元素值相同的多个元素进行删除,只保留唯一一个值节点 。

 

对上面对象l1进行元素去重:

l1.unique();
	cout << "去重后的链表:";
	for (auto& e : l1) {
		cout << e << " ";
	}
	cout << endl;

结果: 

 

        这里讲一下unique函数的真正用法,虽然unique函数可以对链表进行元素去重,但前提是该链表一定处于完全有序的状态才行!!! 

        若链表不是有序的,去重也就是无效的!!!

错误案例如下:

    list<int> l2;
	l2.push_back(34);
	l2.push_back(100);
	l2.push_back(26);
	l2.push_back(79);
	l2.push_back(83);
	l2.push_back(0);
	l2.push_back(34);
	l2.push_back(55);
	l2.push_back(13);
	cout << "原链表:";
	for (auto& e : l2) {
		cout << e << " ";
	}
	cout << endl;
	l2.unique();
	//注:34仍是俩个,没有被去除
	cout << "去重后的链表:";
	for (auto& e : l2) {
		cout << e << " ";
	}
	cout << endl;

 

        原链表是无序的,使用unique函数后,该链表还是有多个重复元素存在!

        最后强调一下:list容器的sort排序函数并不好用,排序效率低下,尽量少用!若想进行高效排序,可以利用vector容器搭配std库中的sort函数进行。 

方法如下:

void Test_Sort(){
    list<int> lt1;
    lt1.push_back(15);
    lt1.push_back(9);
    lt1.push_back(3);
    lt1.push_back(10);
    lt1.push_back(80);    
    lt1.push_back(5);
    lt1.push_back(-3);
    lt1.push_back(0);
    lt1.push_back(42);
    //假设链表中有这么多数据

    vector<int> v;    //创建vector对象
	v.reserve(9);    //根据链表对象的数据个数开辟空间

	//通过遍历lt1链表,将链表中的数据一个一个尾插到vector对象v中,
	for (auto e : lt1)
	{
		v.push_back(e);
	}
	//使用vector方式进行std库中的sort排序
	sort(v.begin(), v.end());
	size_t i = 0;
	//最后将vector排好序的数据在传回lt1中
	for (auto& e : lt1){
		e = v[i++];
	    }
    }

        若是list容器对象需要排序的数据量过大的话,利用vector排序+sort的方式可比直接用list.sort()效率要高很多很多。

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

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

相关文章

前端面试题 —— React (二)

目录 一、React 组件中怎么做事件代理&#xff1f;它的原理是什么&#xff1f; 二、React.Component 和 React.PureComponent 的区别 三、Component, Element, Instance 之间有什么区别和联系&#xff1f; 四、React声明组件有哪几种方法&#xff0c;有什么不同&#xff1f…

数学建模-MATLAB三维作图

导出图片用无压缩tif会更清晰 帮助文档&#xff1a;doc 函数名 matlab代码导出为PDF 新建实时脚本或右键文件转换为实时脚本实时编辑器-全部运行-内嵌显示保存为PDF

120个颠覆你认知的gpt使用案例汇总,办公效率提高500%

文章目录 介绍1.代码生成2.代码注释3.代码解释器4.充当 Linux 终端5.代码纠正6.英语口语练习7.专业的翻译8.面试官9.写任何考科目的作业10.快速解决学习中的任何问题11.网站推荐12.网络工具软件推荐13.快速学习新技能14.快速总结长文本的核心思想15.解决日常办公问题16.制作各种…

【CASA】生态系统NPP及碳源、碳汇模拟(土地利用变化、未来气候变化、空间动态模拟)

碳中和可以从碳排放&#xff08;碳源&#xff09;和碳固定&#xff08;碳汇&#xff09;这两个侧面来理解。陆地生态系统在全球碳循环过程中有着重要作用&#xff0c;准确地评估陆地生态系统碳汇及碳源变化对于研究碳循环过程、预测气候变化及制定合理政策具有重要意义。CASA(C…

【QT 网络云盘客户端】——实现文件属性窗口

目录 文件属性对话框 设置字体样式 获取文件的信息 显示文件属性对话框 当我们点击文件中的属性&#xff0c;则会弹出一个属性对话框&#xff1a; 实现过程&#xff1a; 0.设置 属性 菜单项的槽函数。 1.鼠获取鼠标选中的QListWidgetItem,它包含 图标和文件名 2.根据文件…

Dooring-Saas低代码技术详解

hello, 大家好, 我是徐小夕, 今天和大家分享一下基于 H5-Dooring零代码 开发的全新零代码搭建平台 Dooring-Saas 的技术架构和设计实现思路. 背景介绍 3年前我上线了第一版自研零代码引擎 H5-Dooring, 至今已迭代了 300 多个版本, 主要目的是快速且批量化的生产业务/营销过程中…

CSS Flex 笔记

1. Flexbox 术语 Flex 容器可以是<div> 等&#xff0c;对其设置属性&#xff1a;display: flex, justify-content 是沿主轴方向调整元素&#xff0c;align-items 是沿交叉轴对齐元素。 2. Cheatsheet 2.1 设置 Flex 容器&#xff0c;加粗的属性为默认值 2.1.1 align-it…

Spring 事务的使用、隔离级别、@Transactional的使用

Spring事务是Spring框架提供的一种机制&#xff0c;用于管理应用程序中的数据库事务。 事务是一组数据库操作的执行单元&#xff0c;要么全部成功提交&#xff0c;要么全部失败回滚&#xff0c;保证数据的一致性和完整性。 Spring事务提供了声明式事务和编程式事务两种方式&am…

[Tools: Camera Conventions] NeRF中的相机矩阵估计

参考&#xff1a;NeRF代码解读-相机参数与坐标系变换 - 知乎 在NeRF中&#xff0c;一个重要的步骤是确定射线&#xff08;rays&#xff09;的初始点和方向。根据射线的初始点和方向&#xff0c;和设定射线深度和采样点数量&#xff0c;可以估计该射线成像的像素值。估计得到的…

Live Market:中国“一带一路”十周年,品牌出海跨境电商成为新引擎

​中国提出的“一带一路”倡议已经迎来10周年。高质量共建“数字丝绸之路”是这一倡议的重点方向&#xff0c;能够巩固互联互通合作基础、拓展国际合作新空间、扎牢风险防控网络&#xff0c;实现更高合作水平、更高投入效益、更高供给质量、更高发展韧性&#xff0c;推动共建“…

Python教程三:Python基本概念

1、Python基本语法 Python中严格区分大小写Python中每一行就是一条语句&#xff0c;每条语句以换行结束每一行语句不建议过长&#xff08;一般不建议超过80个字符&#xff09;一条语句可以多行编写&#xff0c;语句后加\结尾Python是缩进严格的语言&#xff0c;所以在Python中…

简单认识NoSQL的Redis配置与优化

文章目录 一、关系型数据库与非关系型数据库1、关系型数据库&#xff1a;2、非关系型数据库3、关系型数据库和非关系型数据库区别&#xff1a;4、非关系型数据库应用场景 二.Redis1、简介2、优点&#xff1a;3、Redis为什么这么快&#xff1f; 三、Redis 安装部署1、安装配置2、…

IDEA配置maven3.6.1时报错: 不支持发行版本 5 或 java: 不再支持源选项 5。请使用 7 或更高版本。

环境&#xff1a;Win10 IDEA 2022.3.3&#xff0c;JDK16&#xff0c;配置maven3.6.1 生成工程后&#xff0c;运行程序&#xff0c;结果报错如下&#xff1a; 不支持发行版本 5 好&#xff0c;此时更改以下选项&#xff1a; 此处我改为16&#xff0c;因为我的JDK是16版本的…

C#实现数字验证码

开发环境&#xff1a;VS2019&#xff0c;.NET Core 3.1&#xff0c;ASP.NET Core API 1、建立一个验证码控制器 新建两个方法Create和Check&#xff0c;Create用于创建验证码&#xff0c;Check用于验证它是否有效。 声明一个静态类变量存放列表&#xff0c;列表中存放包含令…

【论文阅读】定制化diffusion微调: DreamBooth原理

论文&#xff1a;DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation 项目&#xff1a;DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation 代码&#xff1a;Dreambooth-Stable-Diffusion 1. 任务简…

8. Spring Boot 日志文件

目录 1. 日志的作用 2. 如何使用日志 3. 自定义日志打印 3.1 获取日志对象 3.2 设置打印的内容 3.3 常见的日志框架 3.4 日志格式说明 4. 日志级别 4.1 日志级别的作用 4.2 日志级别的分类 4.3 日志级别的使用 4.4 设置日志级别 4.5 分目录设置日志级别 5. 日志…

达梦数据库-下载安装、基本操作及报错处理

下载安装 懒得记官网直接上网搜 产品下载-达梦数据 里面我是按图选择的Dm8 X86 Win64 下载完成后 解压 得到两个文件,打开上面这个ISO文件 打开安装包 setup.exe 这里默认选择中国时间 根据指示一步一步安装即可 选择刚刚安装的DM管理工具即可进入 基本操作 -- 获取所有…

SOLIDWORKS PDM只读文件的处理方法

如果用户检出一个文件&#xff0c;该文件在 SolidWorks 或其他应用程序中仍然以只读形式装入&#xff0c;最常见的原因包括&#xff1a; 1. 核实正在检出的文件尚未在现有 SolidWorks 进程中以只读方式打开。 这是一个常见错误&#xff0c;用户已经在 SolidWorks 打开了装配体…

MySQL界面客户端及高级的复杂查询

十五、MySQL界面客户端 十六、高级的复杂查询 1、查询去重 2、分组查询 gender和name没有同时相同的&#xff0c;相当于没分组 3、别名的使用 4、分组后的筛选 5、排序 6、分页 7、查询的顺序

Vue源码学习 - 异步更新队列 和 nextTick原理

目录 前言一、Vue异步更新队列二、nextTick 用法三、原理分析四、nextTick 源码解析1&#xff09;环境判断2&#xff09;nextTick() 五、补充 前言 在我们使用Vue的过程中&#xff0c;基本大部分的 watcher 更新都需要经过 异步更新 的处理。而 nextTick 则是异步更新的核心。…