【C++】—— list 的了解与使用

news2024/11/17 7:48:22

【C++】—— list 的了解与使用

  • 1 list 的函数接口
  • 2 迭代器
    • 2.1 简单使用 list 的迭代器
    • 2.2 迭代器的划分
    • 2.3 不同迭代器的使用场景
      • 2.3.1 sort
      • 2.3.2 reverse
      • 2.3.3 find
  • 3 emplace_back
  • 4 操作函数
    • 4.1 sort
      • 4.1.1 list中sort介绍
      • 4.1.2 list 中 sort 与算法库中 sort 效率比较
    • 4.2 merge
    • 4.3 unique
    • 4.4 remove
    • 4.5 splice

1 list 的函数接口

  STL库中的 l i s t list list,其底层是一个带头双向循环链表

  STL库 的容器都有很强的相似性,我们有了前面 s t r i n g string string v e c t o r vector vector 的基础,再来学习 l i s t list list 就会轻松很多。
  我把 l i s t list list 的函数接口放出来,相信都加看一眼就知道如何使用了。

在这里插入图片描述

成员函数

在这里插入图片描述

迭代器

在这里插入图片描述

容量

在这里插入图片描述

元素访问

在这里插入图片描述

修改

  上述接口我们都很熟悉了,本文就不再一一进行介绍,大家自行查阅文档即可


  但是关于操作的接口我们还比较陌生,等下我们会一一学习

在这里插入图片描述

操作

  
  

2 迭代器

2.1 简单使用 list 的迭代器

  我们先来简单使用一下 l i s t list list 的迭代器

void test1()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);
	list<int>::iterator it = l1.begin();
	while (it != l1.end())
	{
		cout << *it << endl;
		++it;
	}
}

运行结果:

在这里插入图片描述

  可以看到, l i s t list list 的迭代器访问和 s t r i n g string string v e c t o r vector vector 等是一样的。

  那么 l i s t list list 的迭代器可不可以使用 + 呢?

l1.insert(l1.begin() + 3, 10);

不可以的!

  那既然不可以直接 +3,我们想在第三个位置之前插入数据怎么办呢?

方法如下:

void test1()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	l1.push_back(5);

	auto it = l1.begin();
	int k = 3;
	while (k--)
	{
		++it;
	}
	l1.insert(it, 10);

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

运行结果:

在这里插入图片描述

  
  

2.2 迭代器的划分

  这里,我先来给大家介绍一下迭代器的划分

功能上进行划分

  • iterator
  • reverse_iterator
  • const_iterator
  • const_reverse_iterator

性质上进行划分

  • 单向迭代器 f o r w a d forwad forwad l i s t list list / u n o r d e r e d unordered unordered m a p map map / u n o r d e r e d unordered unordered_ s e t set set 等为单向迭代器。他们只支持 ++
  • 双向迭代器 l i s t list list / m a p map map / s e t set set 等都是双向迭代器。他们支持++/–,但不支持+/-。
  • 随机迭代器 v e c t o r vector vector / s t r i n g string string / d e q u e deque deque 等都是随机迭代器。他们支持++/–/+/-
  • 决定迭代器的性质的是容器的底层结构。

   l i s t list list 的迭代器是一个双向迭代器

在这里插入图片描述

  
  

2.3 不同迭代器的使用场景

  决定迭代器的性质的是容器的底层结构。而底层结构也决定了容器可以使用那些算法
  

2.3.1 sort

在这里插入图片描述

  用 s o r t sort sort 算法进行排序,并不是传什么迭代器都可以的,必须传随机迭代器,否则就会报错。
  为什么呢?因为 s o r t sort sort 底层是快速排序。快排里面要做类似三数取中的东西,它需要支持随机访问。
  

2.3.2 reverse

在这里插入图片描述

   r e v e r s e reverse reverse 是将指定范围内的数据进行翻转。

在这里插入图片描述

  这个算法底层用了 '-'操作符,因此要传双向迭代器

  那 v e c t o r vector vector s t r i n g string string 这些随机迭代器能用逆置算法吗?
  肯定。因为他们功能上是一个包含的关系,双向是一种特殊的单向,随机是一种特殊的双向
  

2.3.3 find

在这里插入图片描述

  那 f i n d find find 算法又需传递什么迭代器呢?
  InputIterator 是什么迭代器呢?它不是单向,双向,随机种的任意一种

这里我们再简单介绍一下:

在这里插入图片描述

  库里面对迭代器性质的定义使用了 C++ 中继承的概念,继承就是子类是一个特殊的父类,所以它认为这里的单向、双向、随机是一个继承关系随机是一个特殊的双向 ,双向是一个特殊的单向
  同时,库中引申出了两个不存在的迭代器只读和只写迭代器(严格来说没有容器的迭代器类型对应这两类,是抽象的概念)。InputIterator迭代器 意味着单向、双向、随机都是其子类。
  出现InputIterator就说明可以给任意类型的迭代器
  
  这里因为 f i n d find find 底层只用了 ++

在这里插入图片描述

  
  

3 emplace_back

  现阶段,我们可以认为 push_backemplace_back 是一样的,都是尾插一个数据

void test2()
{
	list<int> l1;
	l1.emplace_back(1);
	l1.emplace_back(2);
	l1.emplace_back(3);
	l1.emplace_back(4);
	l1.emplace_back(5);
	list<int>::iterator it = l1.begin();
	while (it != l1.end())
	{
		cout << *it << endl;
		++it;
	}
}

运行结果:

在这里插入图片描述

  但是在用法上,如果插入数据的参数是多个的,emplace_back效率会高一些
  
假设我们现在要插入自定义类型 A

struct A
{
	A(int a1 = 1, int a2 = 1)
		:_a1(a1)
		,_a2(a2)
	{}

	int _a1;
	int _a2;
};

  

对应插入自定义类型 A 有两种常见的方法

  • 插入有名对象
  • 插入匿名对象
void test3()
{
	list<A> lt;

	A aa1(1, 1);
	lt.push_back(aa1);
	lt.push_back(A(2, 2));

	lt.emplace_back(aa1);
	lt.emplace_back(A(3, 3));
}

  这两种方式 p u s h push push b a c k back back e m p l a c e emplace emplace b a c k back back 都支持
  
  但是 emplace_back 还支持这样写:

void test4()
{
	list<A> lt;
	lt.emplace_back(3, 3);
}

   e m p l a c e emplace emplace_ b a c k back back 支持直接传构造 A 的参数。
  这里不是隐式类型转换,现阶段我们先不管其底层,学会用法即可。
  
  

4 操作函数

4.1 sort

4.1.1 list中sort介绍

在这里插入图片描述

  我们前面看到,算法库中的 sort 要求是随机迭代器 l i s t list list 的迭代器并不符合,因此它自己实现了一个排序算法。和算法库中的 s o r t sort sort 一样, l i s t list list 中的 s o r t sort sort 排序默认排的是升序,如果要排降序则要用到仿函数(后面会讲)。
   l i s t list list 实现的 s o r t sort sort 底层用的是归并排序,而算法库中的 s o r t sort sort 底层用的是快速排序

void test5()
{
	list<int> lt;
	lt.push_back(3);
	lt.push_back(5);
	lt.push_back(4);
	lt.push_back(1);
	lt.push_back(2);

	lt.sort();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.sort(greater<int>());
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果:

在这里插入图片描述

  

4.1.2 list 中 sort 与算法库中 sort 效率比较

  虽然 l i s t list list 中实现了 s o r t sort sort 排序算法,但是它的排序效率很低,尽量不要用它来排序。

  我们将他与算法库中的 s o r t sort sort 进行性能对比

  • 我们产生 1000000 个相同的数,放进 v e c t o r vector vector l i s t list list 中,再分别用算法库中 s o r t sort sort,和 l i s t list list s o r t sort sort 排序,看运行时间
void test10()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	vector<int> v;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		lt1.push_back(e);
		v.push_back(e);
	}

	int begin1 = clock();
	// 排序
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("vector sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

运行结果:

在这里插入图片描述

  差距 2 倍多

  • 这一次我们用两个链表进行排序:一个链表将数据拷贝进 v e c t o r vector vector,用库中的 s o r t sort sort 排序,后再拷贝回来;另一个直接调用 l i s t list list 中的 s o r t sort sort
void test11()
{
	srand(time(0));
	const int N = 1000000;

	list<int> lt1;
	list<int> lt2;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand() + i;
		lt1.push_back(e);
		lt2.push_back(e);
	}

	int begin1 = clock();
	// 拷贝vector
	vector<int> v(lt2.begin(), lt2.end());

	// 排序
	sort(v.begin(), v.end());

	// 拷贝回lt2
	lt2.assign(v.begin(), v.end());

	int end1 = clock();

	int begin2 = clock();
	lt1.sort();
	int end2 = clock();

	printf("list copy vector sort copy list sort:%d\n", end1 - begin1);
	printf("list sort:%d\n", end2 - begin2);
}

  


  上述代码用了 l i s t list list 中的 a s s i g n assign assign 接口,我们简单介绍一下

在这里插入图片描述

   a s s g i n assgin assgin 功能是用一段迭代器区间对调用函数的 l i s t list list 对象进行拷贝,任何容器的迭代器都可以。像 v e c t o r vector vector 等都有 a s s g i n assgin assgin 接口

运行结果:

在这里插入图片描述

  可以看到,即使多了两次拷贝,依然是算法库中的 sort 效率更高。同时这也说明了拷贝的代价其实是很低的
  

4.2 merge

在这里插入图片描述

   m e r g e merge merge 接口的功能是:将两个链表合并。合并的前提是两个链表是有序的。

void test6()
{
	std::list<double> first, second;

	first.push_back(3.1);
	first.push_back(2.2);
	first.push_back(2.9);

	second.push_back(3.7);
	second.push_back(7.1);
	second.push_back(1.4);

	first.sort();
	second.sort();

	first.merge(second);

	for (auto e : first)
	{
		cout << e << endl;
	}
}

运行结果:

在这里插入图片描述

  需要注意:合并会让其中一个链表空掉。
  其底层是创建一个新链表,依次去两个链表中小的尾插,最后再将新链表与first链表进行交换。

  

4.3 unique

在这里插入图片描述

   u n i q u e unique unique 是一个去重接口,但它要求数据必须是有序的

void test7()
{
	std::list<int> lt;

	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(4);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(5);
	lt.push_back(1);
	lt.push_back(5);
	lt.push_back(2);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	lt.sort();
	lt.unique();

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

运行结果:

在这里插入图片描述

  

4.4 remove

在这里插入图片描述

   r e m o v e remove remove 接口是对一个值进行删除,他和 e r a s e erase erase 有点像。不同的是 e r a s e erase erase 是传一个迭代器 r e m o v e remove remove 是传一个,我找到了我就删,没找到也不会报错

  

4.5 splice

在这里插入图片描述

   s p l i c e splice splice 是粘贴的意思,但这函数接口功能更像剪切
   s p l i c e splice splice 的功能本质是一种转移 x x x 链表中的元素转移到调用该函数的 p o s i t i o n position position 位置之前(是转移不是粘贴)
  
实例:将 m y l i s t 2 mylist2 mylist2 数据转移到 m y l i s t 1 mylist1 mylist1 中 2 的前面

void test8()
{
	std::list<int> mylist1, mylist2;
	std::list<int>::iterator it;

	// set some initial values:
	for (int i = 1; i <= 4; ++i)
		mylist1.push_back(i);      // mylist1: 1 2 3 4

	for (int i = 1; i <= 3; ++i)
		mylist2.push_back(i * 10);   // mylist2: 10 20 30

	it = mylist1.begin();
	++it;							// points to 2

	mylist1.splice(it, mylist2);	// mylist1: 1 10 20 30 2 3 4
									// mylist2 (empty)
									// "it" still points to 2 (the 5th element)
	cout << "mylist1:";
	for (auto e : mylist1)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "mylist2:";
	for (auto e : mylist2)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果:

在这里插入图片描述

  
   s p l i c e splice splice 还有以下用法:调整当前链表节点的顺序
  比如我想将第一个链表中的 5 放在第一个,怎么做呢

void test9()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);

}

  第一种方法就是将 5 这个节点删除,再进行头插。但这一来一去又是删除又是 n e w new new 的,效率较低。
  我们还有一种方法:运用 splice 接口 s p l i c e splice splice 允许自己转移给自己。

void test9()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);
	lt.push_back(6);

	list<int>::iterator it = find(lt.begin(), lt.end(), 5);
	if (it != lt.end())
	{
		lt.splice(lt.begin(), lt, it);
	}
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

运行结果:

在这里插入图片描述

  
  不仅如此,我们函转移一段范围

list<int>::iterator it = find(lt.begin(), lt.end(), 4);
if (it != lt.end())
{
	lt.splice(++lt.begin(), lt, it, lt.end());
}

运行结果:

在这里插入图片描述

  
  
  
  
  


  好啦,本期关于 l i s t list list 的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在 C++ 的学习路上一起进步!

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

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

相关文章

软件测试面试少走弯路

自我介绍开场白 只会手工和会写基础脚本分别如何介绍 自动化性能都会该如何介绍&#xff1f;记得面试前准备好如何回答怎么做到的&#xff1f; 项目如何进行介绍 回答验证码机制的处理问题 不会自动化和性能能找到工作吗&#xff1f; 萌芽计划对软件测试的大致了解 自动化测试…

操作系统 ---- 调度算法【先来先服务(FCFS)、最短作业优先(SJF)、最高响应比优先(HRRN)】

目录 一、常见的调度算法 1. 先来先服务&#xff08;FCFS, First-Come, First-Served&#xff09; 2. 最短作业优先&#xff08;SJF, Shortest Job First&#xff09; 3. 优先级调度&#xff08;Priority Scheduling algorithm&#xff0c;PSA&#xff09; 4. 轮转调度&am…

嵌入式-QT学习-小练习

1. 实现多窗口 2. 给按键增加图标 3. 动图展示 结果演示&#xff1a; Mul_Con main.cpp #include "widget.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }一、第一个窗口展示 …

阿里云 EMR StarRocks 在七猫的应用和实践

七猫公司简介 七猫是一家深耕文化娱乐行业的互联网企业&#xff0c;总部坐落在上海市前滩中心。七猫旗下原创文学网站七猫中文网于2017年5月正式上线&#xff0c;专注为原创作者提供创作指导、版权运营等全方位一体化服务。七猫拳头产品七猫免费小说App于2018年8月正式上线&am…

力扣213-打家劫舍 II(Java详细题解)

题目链接&#xff1a;213. 打家劫舍 II - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 本体是打家劫舍的一个变形题&#xff0c;希望大家能先做198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09;&#xff0c;并看一下我上题的讲解力扣198-打家劫舍&…

TESSY创建需要手写桩的测试用例

如果需要让桩函数有额外的功能&#xff0c;如&#xff1a;传参检测、局部数据处理、多传参检测、函数实现变更等&#xff0c;可以进行手写桩。 我们以tessy5.1 IDE为例&#xff0c;给大家展示编写一个需要手写桩的测试用例过程。 1、前期的准备工作 可以参考以下文章&#xff1…

海运系统推荐:如何实现海运物流轨迹跟踪管理?

在海运业务中&#xff0c;物流信息的及时更新与透明化至关重要。然而&#xff0c;许多从事海运的企业和个人常常面临客户的连环追问&#xff0c;这些问题成为日常工作中的痛点&#xff1a;“我的货到哪了&#xff1f;”“怎么还没更新物流信息&#xff1f;”这样的情形让人感到…

错误: 编码GBK的不可映射字符的解决方法

之前我一直用的eclipse来编写java代码&#xff0c;从来没有出现过这个错误&#xff0c;但是转到VS中后我写个中文注释都没法写&#xff0c;写了就报错&#xff0c;于是开始探索原因 出现这种问题大概率你是在官网下载的JDK&#xff0c;默认是国际版的&#xff0c;他在编译时如果…

828华为云征文|基于华为云Flexus云服务器X实现个人博客搭建

文章目录 ❀前言❀部署前准备❀宝塔安装❀安全组开放❀web访问验证❀安装docker❀安装wordpress❀安全组开放18040端口❀访问博客网址❀发布个人博客❀总结 ❀前言 大家好&#xff0c;我是早九晚十二。 近期华为云推出了最新的华为云Flexus云服务器X&#xff0c;这款云主机在算…

TI DSP下载器XDS100 V2.0无法使用问题

前言 TI DSP下载器XDS100 V2.0用着用着会突然报Error&#xff0c;特别是你想要用Code Composer Studio烧录下载程序的时候 查看设备管理器&#xff0c;发现XDS100 V2.0的设备端口莫名其妙消失了 问了淘宝的厂家&#xff0c;他说TI的开发板信号可能会导致调试器通信信号中断&a…

ant.design【点击展示详细信息】

第一部分&#xff1a;const [Visit,setVisit]useState(false);const [data,setdata] useState({});第二部分&#xff1a; render: (text, record) > [ <a style{{marginRight:"2%"}} onClick{()>{ setVisit(true) setdata(record) }} > 详细 </a>…

【HarmonyOS】Beta最新对外版本IDE下载和环境配置

【HarmonyOS】Beta最新对外版本IDE下载和环境配置 前言 目前华为HarmonyOS的系统版本已经从Develop Beta升级为Beta预览版&#xff0c;全面开放。再也不需要白名单限制&#xff0c;才能下载使用最新的IDE和预览最新的开放文档了。 IDE下载和安装 Beta IDE下载地址 1.根据你…

linux-L9.linux中对文件 按照时间排序 显示100 个

find . -type f -exec stat --format %Y %n {} | sort -nr | head -n 100解释&#xff1a; • find . -type f&#xff1a;在当前目录下查找所有文件。 • -exec stat --format ‘%Y %n’ {} &#xff1a;对每个找到的文件执行stat命令&#xff0c;以获取文件的修改时间&#…

stm32 W25Q数据存储

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、cubemx配置二、keil中文件修改与配置三、几个重要函数的说明四、DMA方式传输&#xff08;待写&#xff09;总结 前言 W25Q128 容量为128位 128/8 16 也就…

为什么要进行MySQL增量备份?

进行MySQL增量备份的原因主要包括以下几点&#xff1a; 节省存储空间&#xff1a;增量备份只备份自上次全量或增量备份以来更改过的数据&#xff0c;而不备份所有数据。相比全量备份&#xff0c;增量备份生成的文件通常较小&#xff0c;可以显著减少存储空间的使用。减少备份时…

学习平台|基于java的移动学习平台系统小程序(源码+数据库+文档)

学习平台|学习平台系统|在线学习平台系统小程序 目录 基于java的移动学习平台系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码…

合宙Air201资产定位模组LuatOS入门课程:FOTA远程升级,点点鼠标就搞定

你是否也经常吐槽&#xff1a;开发是个苦差事&#xff01;做项目一时爽&#xff0c;遇到升级火葬场。 如果你也有这种困惑&#xff0c;可以多了解了解合宙的开发工具&#xff0c;简单实用又高效&#xff0c;甚至只需点点鼠标&#xff01; 本期&#xff0c;我们来学习合宙Air2…

Ubuntu 20.04 Linux无法访问GitHub问题

Ubuntu 20.04 Linux无法访问GitHub问题 使用ip查找在线工具&#xff1a;工具查询 http://github.com和http://github.global.ssl.fastly.net的ip地址 终端输入&#xff1a; sudo gedit /etc/hosts 打开hosts文件&#xff1b;将刚刚两个ip地址输入到hosts文件中。 wq关掉并保存…

【D3.js in Action 3 精译_022】3.2 使用 D3 完成数据准备工作

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

【油猴脚本】00004案例 Tampermonkey油猴脚本引入js库,使表格可以拖拽移动

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【油…