【C++】STL——list的使用

举报
YIN_尹 发表于 2023/09/25 21:36:01 2023/09/25
【摘要】 前言这篇文章我们来继续STL的学习,今天我们要学习的是list,也是STL中容器的一员。和之前一样,我们还是先学习它的使用,然后再对它进行一个深度剖析和模拟实现。1. list的介绍及使用1.1 list的介绍list的文档介绍list的底层实现其实就是我们之前数据结构学过的带头双向循环链表:1.2 list的使用首先我们来学习一下list的使用:那经过之前string和vector的学习,...

前言

这篇文章我们来继续STL的学习,今天我们要学习的是list,也是STL中容器的一员。

和之前一样,我们还是先学习它的使用,然后再对它进行一个深度剖析和模拟实现。

9033db7c135c40dfa31febac9b85ac27.png

1. list的介绍及使用

1.1 list的介绍

list的文档介绍

acc7b9877133425db1fb7c379dcaaf63.png

list的底层实现其实就是我们之前数据结构学过的带头双向循环链表

0aa38314674f40c786bbf19a6527a643.png

b9d4bd3f8907449480892cbd6b92a362.png

092e06e022474e2c876f4a064002018f.png

1.2 list的使用

首先我们来学习一下list的使用:

那经过之前string和vector的学习,我们想要学会list的使用,成本就很低了,所以下面我们就带大家快速的过一下,我们的重点还是在于后面的模拟实现。

我们来看一下它的接口:

首先看一下构造:

7c0f3d80adcd4fb0abe6cc0c6b2393e8.png

也是我们熟悉的这几个,默认构造、n个val的构造、迭代器区间的构造以及拷贝构造。

然后看一下它的迭代器:

67466f7528fb4421b11362cb2d17b728.png

也是这几个,相信学到现在大家都很熟悉了。

修改操作:a81f3f54744342f9a9be1ce4d55d05f8.png

这里面常用的几个接口我们也都比较熟悉。

但是我们看到list这里只有resize,没有reverse了,因为它是链表嘛,就没有扩容这一说了。

418e84f6ced541f4aadf3ba2bd36541c.png

那剩余的比较重要的接口我们后面讲到再说。

但是我们会注意到:


list与string和vector最大的区别是啥?

我们会发现list没有重载[],也就是说我们要遍历和访问list,就只能用迭代器了(范围for的底层也是迭代器)。

所以说,迭代器才是通用的方式,所有的容器都可以用迭代器,而[]只是针对特定容器的特殊方式。

遍历

那经过之前的学习,相信大家就可以直接上手使用list的迭代器了:

int main()
{
    list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.push_back(3);
    l.push_back(5);
    for (list<int>::iterator it = l.begin(); it != l.end(); ++it)
        cout << *it << " ";
    cout << endl;

    for (auto e : l)
        cout << e << " ";
    cout << endl;

    for (list<int>::reverse_iterator rit = l.rbegin(); rit != l.rend(); ++rit)
        cout << *rit << " ";
    cout << endl;
    return 0;
}

96243a5e7ba64a508a5213251f5634f1.png

插入删除数据

然后我们来演示一下insert和erase:

我们发现list也没有提供find,所以我们要获取某个位置的迭代器,可以用算法库里面的find:1f91838038984eb89fe5b85b1187b808.png

7b76dbd1cdd440f082595db076d17cd9.png

也是这几个版本,就不给大家全部演示了。

然后erase:

871e7755e2264c7b8d9870beb10754b0.png

791b330f81304c33b19a9a51f89d4ee8.png但是注意list的迭代器是双向迭代器:

8b0caf8c6cb746d6af8aaf6c1db403f6.png

只能++或者- -,不能+或-

405bee4d8e35404ba2ec12ab90ae7c97.png

Operations

然后来看下这几个接口:

0094c350612c4d4ba39f2c00d5e7e4fd.png首先这个splice ,用的不多,它可以把一个链表的一部分转移到另一个链表

e53cd5d987f44b84b63002dfce106a3c.png

大家需要的时候自己看一下文档就会用了。

然后remove就是删除指定的元素,find+erase

f116e956c7514a91b342eb4fb5a80256.png

后面还有个remove_if,这个涉及仿函数,我们先不用管。

然后unique就是去重:

7e22aceb60374610af53385d168b4706.png


merge可以合并两个有序链表:

6785ad7b3857491794973f0ac30a50b7.png

然后呢,list也提供了sort

就是可以对链表进行排序:

d388839d6df844e29dbfe5cb7063fd73.png

最后reverse就是对链表逆置,就不多说了。

那我们接下来思考一个问题:算法库里面不是已经有sort了吗,为什么链表自己还要提供一个sort?

最主要的原因是算法库里的排序list就用不了。

ac8e841b5c334fd38994ace4a1038fb2.png

我们发现报了一堆错怎么,回事呢?

4edb0c664f084dc382c74e2ba070fd58.png

我们看到算法库的sort进行了什么,是不是-啊?

但是我们上面说了,**list的迭代器是双向迭代器,是不能进行-操作的。**当然除此之外里面其它操作list也不行。

迭代器的功能分类

所以呢:

094a7072836546f8a32be0f6149d8e35.png

虽然库里的sort是一个函数模板,理论而言这里可以传任意类型的参数,但是其内部对使用的迭代器有要求,参数的名字就暗示了我们要传随机迭代器。

当然不同容器对应的迭代器是什么类型跟它的底层结构有关系。

那我们之前文章也提到过:

迭代器我们之前讲的什么正向反向,const迭代器,这些是使用属性;那还有一个特性属性,迭代器严格来说还可以细分为单向迭代器,双向的和随机的,单向的就是只能++不能- -,双向就是可以++也可以- -,那随机就是除了可以++和- -之外还可以+或- 。

那这个单向,双向,随机大家可以认为是迭代器的功能分类:

1、单向迭代器:只能++,不能- -。例如forward_list和unordered_map;

2、双向迭代器:既能++也能–。例如list;

3、随机访问迭代器:能++ 和- -,也能+和-。例如vector和string。

ce8921a0d9c646139d49a1b3313c243c.png

文档里面在Member types我们能看到当前容器的迭代器类型。

🆗,那除了sort,算法库里的:

ed18ff01ac2e4270ade126127c6b5752.png

我们看到reverse参数名字是不是也有暗示,暗示我们要传双向迭代器

那你传个单向可以吗?

是不是不行啊,因为双向既要支持++还要支持- -,而单向是不是只能++啊:

281f16895bc0457c8ee3c3722ad3f298.png但是我们传随机可以吗?

是不是可以啊,因为随机是支持++和- -的。

🆗 ,那相信现在大家就明白为什么list要自己提供一个sort 了。


44d1233b075f4b878f4e798d035de149.png但是,想告诉大家的是:


list提供了一个sort其实是有点没必要的,大多数情况下我们都不会用list的排序。

为什么,因为效率太慢了。


list 的sort性能测试

现在我这里已经有一段写好的代码用来测试vector和list排序的性能,具体实现大家可以不用关心,看一下结果就行了。

现在产生100000个随机数,分别放到vector和list中,然后list调自己提供的sort,vector调库里面的sort,我们来对比一下它们的运行时间:

76104ed0893f4e6d8e8c7281a89984a5.png

多运行几次:

12708f91a62c4820be81443f13efb273.png

31220bea6f5745f485e0129ee024222d.png

我们看到vector是更快一些在它们排一组相同的数据下。

那我们加到1000000个数据再来看:

a7b8627b1cfd4bcab4e4c26fafd1d959.png

然后我们再换一种玩法:

我们现在定义两个list,还是上面那些数据,一个list我直接排,另一个怎么做呢?

先把它拷贝到一个vector里面去排序,然后排完再拷贝回list,我们来看一下:

5203acf4c24843c2b5c83e0e16e4e091.png

🆗,我们看到还是比直接在list里排快很多。

所以说:

虽然list提供了sort,但是我们大多数情况下是不会选择用它的。

🆗:

那list的使用我们差不多就讲到这里,大家用到哪些接口如果没有讲到可以自行查阅文档。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。