list的学习

news2025/4/22 6:32:57

list的介绍

list文档的介绍
请添加图片描述

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素

list的使用

list中的接口比较多,此处类似,只需要掌握如何正确的使用,然后再去深入研究背后的原理,已达到可扩展的能力。以下为list中一些常见的重要接口。

list的构造

请添加图片描述

explicit list (const allocator_type& alloc = allocator_type());

  • 解释:构造一个空的容器,里面没有任何元素
    `explicit list (size_type n, const value_type& val = value_type(),const allocator_type& alloc = allocator_type());
  • 解释:构造一个包含 n 个元素的容器。每个元素都是 val 的副本
    list (InputIterator first, InputIterator last)
  • 解释:构造一个容器,里面的元素是[first,last),里面的每个元素都来自这个范围里对应的元素,顺序相同 。
    list (const list& x)
  • 解释:构造一个容器,其中包含 x 中每个元素的,顺序相同。
  • 示例:
void test_list1()
{
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 100);                 // l2中放4个值为100的元素
    list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3
    list<int> l4(l3);                    // 用l3拷贝构造l4

    // 以数组为迭代器区间构造l5
    int array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 };

    // 用迭代器方式打印l5中的元素
    list<int>::iterator it = l5.begin();
    while (it != l5.end())
    {
        cout << *it << " ";  //16 2 77 29
        ++it;
    }
    cout << endl;

    // C++11范围for的方式遍历
    for (auto& e : l5)
        cout << e << " ";  //16 2 77 29

    cout << endl;
}

list的遍历

// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{
    // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
    {
        cout << *it << " ";
        // *it = 10; 编译不通过
    }
    cout << endl;
}

1.list iterator的使用

此处,大家可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
iterator begin();const_iterator begin() const;
iterator end();const_iterator end() const;
reverse_iterator rbegin();const_reverse_iterator rbegin() const
reverse_iterator rend();const_reverse_iterator rend() const;
这里的使用方法和string、vector一样,就不再过多介绍了。

注意
1.begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
2.rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动


2.list capacity

empty
bool empty() const;

  • 解释:检测list是否为空,是返回true,否则返回false
  • 示例:
void test_list2()
{
    list<int> l1;
    list<int> l2;
    l1.push_back(1);
    l1.push_back(2);
    l1.push_back(3);
    l1.push_back(4);

    cout << l1.empty() << endl;  //0
    cout << l2.empty() << endl;  //1
}

size
size_type size() const;

  • 解释:返回list中有效节点的个数
    用法跟前面的一样,不在过多阐述。

3.list 的元素的访问

front
reference front();const_reference front() const;

  • 解释:返回list的第一个节点中值的引用
  • 示例:
void test_list3()
{
    list<int> mylist;

    mylist.push_back(77);
    mylist.push_back(22);

    // now front equals 77, and back 22
    mylist.front() -= mylist.back();
    cout << "mylist.front() is now " << mylist.front() << '\n';  //mylist.front() is now 55

}

back
reference back();const_reference back() const;

  • 解释:返回list的最后一个节点中值的引用
  • 示例:
void test_list3()
{
    list<int> mylist;
    mylist.push_back(10);
    while (mylist.back() != 0)
    {
        mylist.push_back(mylist.back() - 1);
    }

    cout << "mylist contains:";
    for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        cout << ' ' << *it;  //mylist contains: 10 9 8 7 6 5 4 3 2 1 0
}

4.list的插入、删除、交换、清空

push_front
请添加图片描述

  • 解释:在list首元素前插入值为val的元素
    pop_front
    请添加图片描述

  • 解释:删除list中第一个元素
    push_back
    请添加图片描述

  • 解释:在list尾部插入值为val的元素
    pop_back
    请添加图片描述

  • 解释:删除list中最后一个元素

  • 示例:

void test_list4()
{
    int array[] = { 1, 2, 3 };
    list<int> L(array, array + sizeof(array) / sizeof(array[0]));

    // 在list的尾部插入4,头部插入0
    L.push_back(4);
    L.push_front(0);
    list<int>::iterator it = L.begin();
    while (it != L.end())
    {
        cout << *it << " ";  //0 1 2 3 4
        ++it;
    }
    cout << endl;

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    list<int>::iterator it1 = L.begin();
    while (it1 != L.end())
    {
        cout << *it1 << " ";  //1 2 3
        ++it1;
    }
}

insert
请添加图片描述

  • 解释:在position位置之前,插入值为val的元素。其它形式的用法和之前一样。
    erase
    请添加图片描述

  • 解释:删除position位置的值或者删除某个区间的所有元素。

  • 示例:

void test_list5()
{
    //这里的PrintList(L)就是上面list的遍历
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));

    // 获取链表中第二个节点
    auto pos = ++L.begin();
    cout << *pos << endl;  //2

    // 在pos前插入值为4的元素
    L.insert(pos, 4);
    PrintList(L);  //1 4 2 3

    // 在pos前插入5个值为5的元素
    L.insert(pos, 5, 5);
    PrintList(L);  //1 4 5 5 5 5 5 2 3

    // 在pos前插入[v.begin(), v.end)区间中的元素
    vector<int> v{ 7, 8, 9 };
    L.insert(pos, v.begin(), v.end());
    PrintList(L);  //1 4 5 5 5 5 5 7 8 9 2 3

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);  //1 4 5 5 5 5 5 7 8 9 3

    // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
    L.erase(L.begin(), L.end());
    PrintList(L);  //
}

swap
请添加图片描述

  • 解释交换两个list中的元素。
    clear
    请添加图片描述

  • 解释:清空list中的有效元素。

  • 示例:

void test_list6()
{
    // 用数组来构造list
    int array1[] = { 1, 2, 3 };
    list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));
    PrintList(l1);  //1 2 3

    // 交换l1和l2中的元素
    list<int> l2(3, 1);
    l1.swap(l2);
    PrintList(l1); //1 1 1
    PrintList(l2); //1 2 3

    // 将l2中的元素清空
    l2.clear();
    cout << l2.size() << endl;  //0
}

5.list的其它操作

sort
请添加图片描述

  • 解释:对列表中的元素进行排序,更改它们在容器中的位置。(默认是按照升序排列)
  • 示例:
void test_list7()
{
    list<int> l1 = { 3,2,1,4,5 };
    auto it = l1.begin();
    while (it != l1.end())
    {
        cout << *it << " ";  //3 2 1 4 5
        ++it;
    }
    cout << endl;
    
	//升序排列:less
    l1.sort();
    for (list<int>::iterator i = l1.begin(); i != l1.end(); i++)
    {
        cout << *i << " ";  //1 2 3 4 5
    }
}

如果想按照降序排列,就按以下的方式写。这里就先展示如何写,到后面的学习在深入讲解这个知识点,也就是“仿函数”。

void test_list7()
{
    list<int> l1 = { 3,2,1,4,5 };
    auto it = l1.begin();
    while (it != l1.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    //降序排列:greater
    //greater<int> gt;
    //l1.sort(gt);
    l1.sort(greater<int>());  //推荐这种写法
    for (list<int>::iterator i = l1.begin(); i != l1.end(); i++)
    {
        cout << *i << " ";  //5 4 3 2 1
    }
}

请添加图片描述

  • 解释:对[first,last)范围内的元素进行排序。也可以通过迭代器对指定范围内的元素进行排序。默认是按升序排序,当然也可以通过仿函数来按照降序排列。
  • 示例:
int main()
{
    vector<int> v = { 6,3,4,5,2,1,7,9,8 };
    sort(v.begin(), v.end());
    for (auto i : v)
    {
        cout << i << " ";  //1 2 3 4 5 6 7 8 9
    }
    cout << endl;

    vector<int> v1 = { 3,2,4,5,6,8,1 };
    sort(v1.begin(), v1.begin() + 4);
    for (auto x : v1)
    {
        cout << x << " ";  //2 3 4 5 6 8 1
    }

	return 0;
}

通过对list和算法库里的sort对比。我们可以知道list里的排序没法使用迭代器来进行排序,因为list的底层是带头双向循环链表,当使用end()时,由于像vector和string里的迭代器不同,它们的end是最后一个元素的下一个位置,而在链表中,链表的物理空间并不连续,end的下一个数据就会指向头结点。所以我们要对迭代器进行一定的封装。让迭代器符合统一的迭代器使用规则。
请添加图片描述

那么如何进行封装呢?等到list的模拟实现的时候在给各位细心讲解。


unique
请添加图片描述

  • 解释:从容器中每个连续的相等元素组中删除除第一个元素之外的所有元素,也就是去除重复元素。注意,只有当元素与紧接其前面的元素相等时,才会从列表容器中删除该元素。因此,此函数对于排好序的列表特别有用。(只对于版本1)
  • 示例:
void test_list9()
{
    list<int> l1 = { 1,2,2,2,3,4,4,2,2,5 };
    l1.unique();

    auto i = l1.begin();
    while (i != l1.end())
    {
        cout << *i << " ";  //1 2 3 4 2 5
        ++i;
    }
    cout << endl;

    list<int> l2 = { 1,1,3,4,2,5,5,5,6 };
    l2.sort();
    l2.unique();
    auto x = l2.begin();
    while (x != l2.end())
    {
        cout << *x << " ";  //1 2 3 4 5 6
        ++x;
    }
}

reverse
请添加图片描述

  • 解释:逆置列表中元素的顺序
  • 示例:
int main()
{
    list<int> mylist;
    for (int i = 1; i < 10; ++i) 
        mylist.push_back(i);

    mylist.reverse();
    cout << "mylist contains:";
    for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
        cout << ' ' << *it;  //mylist contains: 9 8 7 6 5 4 3 2 1

    return 0;
}

list的模拟实现

List的模拟实现

list迭代器失效问题

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

void TestListIterator1()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    auto it = l.begin();
    while (it != l.end())
    {
        // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
        l.erase(it);
        ++it;
    }
}

// 改正
void TestListIterator()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    auto it = l.begin();
    while (it != l.end())
    {
        l.erase(it++); // it = l.erase(it);
    }
}

list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不同,其主要不同如下:

vectorlist
底层结构动态顺序表,一段连续空间带头结点的双向循环链表
随机访问支持随机访问,访问某个元素效率O(1)不支持随机访问,访问某个元素
效率O(N)
插入和删除任意位置插入和删除效率低,需要搬移元素,时间复杂度为O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低任意位置插入和删除效率高,不需要搬移元素,时间复杂度为O(1)
空间利用率底层为连续空间,不容易造成内存碎片,空间利用率高,缓存利用率高底层节点动态开辟,小节点容易造成内存碎片,空间利用率低,缓存利用率低
迭代器原生态指针对原生态指针(节点指针)进行封装
迭代器失效在插入元素时,要给所有的迭代器重新赋值,因为插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,当前迭代器需要重新赋值否则会失效。插入元素不会导致迭代器失效,删除元素时,只会导致当前迭代器失效,其他迭代器不受影响
使用场景需要高效存储,支持随机访问,不关心插入删除效率大量插入和删除操作,不关心随机访问

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

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

相关文章

HarmonyOS:Navigation实现导航之页面设置和路由操作

导读 设置标题栏模式设置菜单栏设置工具栏路由操作页面跳转页面返回页面替换页面删除移动页面参数获取路由拦截 子页面页面显示类型页面生命周期页面监听和查询 页面转场关闭转场自定义转场共享元素转场 跨包动态路由系统路由表自定义路由表 示例代码 Navigation组件适用于模块…

管道位移自动化监测方案

一、背景 管道系统在区域性地质沉降作用下易形成非均匀应力场集中现象&#xff0c;诱发管体屈曲变形及环焊缝界面剥离等连续损伤累积效应&#xff0c;进而导致管道力学性能退化与临界承载能力衰减。传统人工巡检受限于空间覆盖度不足及数据采集周期长&#xff08;≥72h&#xf…

【学习笔记】机器学习(Machine Learning) | 第五周| 分类与逻辑回归

机器学习&#xff08;Machine Learning&#xff09; 简要声明 基于吴恩达教授(Andrew Ng)课程视频 BiliBili课程资源 文章目录 机器学习&#xff08;Machine Learning&#xff09;简要声明 一、逻辑回归的基本原理分类判断条件模型输出的解释Sigmoid 函数与 Logistic 函数逻辑…

Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例

Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例 内容概要 第8章深入探讨了计算机视觉中的深度学习&#xff0c;特别是卷积神经网络&#xff08;convnets&#xff09;的应用。本章详细介绍了卷积层和池化层的工作原理、数据增强技术、预训练模型的特征…

[免费]SpringBoot+Vue博物馆(预约)管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue博物馆(预约)管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue博物馆(预约)管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着计算机科学技术的日渐成熟&#xff…

【python】pyCharm常用快捷键使用-(2)

pyCharm常用快捷键使用 快速导入任意类 【CTRLALTSPACE】代码补全【CTRLSHIFTENTER】代码快速修正【ALTENTER】代码调试快捷键

机器视觉lcd屏增光片贴合应用

在现代显示制造领域&#xff0c;LCD屏增光片贴合工艺堪称显示效果的"画龙点睛"之笔。作为提升屏幕亮度、均匀度和色彩表现的关键光学组件&#xff0c;增光片的贴合精度直接影响着终端用户的视觉体验。传统人工贴合方式难以满足当前超窄边框、高分辨率显示屏的严苛要求…

VScode-py环境

settings.json {"git.ignoreLimitWarning": true,"code-runner.runInTerminal": true,"code-runner.executorMap": {"python": "python3"} } 第二句话保证在终端里面进行IO 第三句话保证python3的用户不会执行python关键…

用键盘实现控制小球上下移动——java的事件控制

本文分享Java的一个有趣小项目&#xff0c;实现用键盘控制小球的移动 涉及java知识点&#xff1a;Swing GUI框架&#xff0c;绘图机制&#xff0c;事件处理&#xff0c;焦点控制 1.编写窗口和面板 (1.)定义面板类 Panel 继承自Java 自带类JPanel (2.)定义窗口类 window 继承…

《马尼拉》桌游期望计算器

《马尼拉》桌游期望计算器&#xff1a;做出最明智的决策 注&#xff1a;本项目仍在开发验证中&#xff0c;计算结果可能不够准确&#xff0c;欢迎游戏爱好者提供协助&#xff01; 在线使用 | GitHub 项目简介 马尼拉期望计算器是一个基于 Vue 3 Vite 开发的网页应用&#xff…

动态LOD策略细节层级控制:根据视角距离动态简化远距量子态渲染

动态LOD策略在量子计算可视化中的优化实现 1. 细节层级控制:动态简化远距量子态渲染 在量子计算的可视化中,量子态通常表现为高维数据(如布洛赫球面或多量子比特纠缠态)。动态LOD(Level of Detail)策略通过以下方式优化渲染性能: 距离驱动的几何简化: 远距离渲染:当…

线程池的介绍

目录 一、什么是线程池 二、线程池的详细内容 三、线程池的简化 一、什么是线程池 提到线程池&#xff0c;我们可能想到 常量池&#xff0c;可以先来说说常量池&#xff1a; 像是字符串常量&#xff0c;在Java程序最初构建的时候&#xff0c;就已经准备好了&#xff0c;等程…

安恒安全渗透面试题

《网安面试指南》https://mp.weixin.qq.com/s/RIVYDmxI9g_TgGrpbdDKtA?token1860256701&langzh_CN 5000篇网安资料库https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247486065&idx2&snb30ade8200e842743339d428f414475e&chksmc0e4732df793fa3bf39…

计算机是如何工作的(上)

对于学习JavaEE初阶为什么要知道计算机是如何工作的&#xff0c;是因为在未来我们写代码的时候&#xff0c;会出现一些bug&#xff0c;而在代码层面是看不出来的&#xff0c;所以我们需要了解一些关于计算机内部是如何工作的&#xff0c;从而提高代码的健壮度。 计算机的组成&…

基础服务系列-Windows10 安装AnacondaJupyter

下载 https://www.anaconda.com/products/individual 安装 安装Jupyter 完成安装 启动Jupyter 浏览器访问 默认浏览器打开&#xff0c;IE不兼容&#xff0c;可以换个浏览器 修改密码 运行脚本

Kubernetes架构介绍

实验环境 安装好k8s集群 一、kubernetes组件构成 1、架构图 2、组件介绍 使用以下命令查看相关资源 kubectl get nodes 查看群集节点 kubectl get ns 查看名称空间 kubectl get pod -A …

远程服务器的mysql连接不上,问题出在哪里

使用本地ideal测试连接报错记录 排查 检查mysql服务是否正常,输入命令systemctl status mysql查看 检查端口netstat -plnt | grep mysql 最后检查服务器的防火墙设置 我以为在服务器厂商的控制面板设置放行规则就行&#xff0c;导致一直无法排查出问题&#xff0c;最后才发现由…

Java高频面试之并发编程-04

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;调用 start()方法时会执行 run()方法&#xff0c;那为什么不直接调用 run()方法&#xff1f; 多线程中调用 start() 方法…

【第16届蓝桥杯软件赛】CB组第一次省赛

个人主页&#xff1a;Guiat 归属专栏&#xff1a;算法竞赛 文章目录 A. 移动距离&#xff08;5分填空题&#xff09;B. 客流量上限&#xff08;5分填空题&#xff09;C. 可分解的正整数D. 产值调整E. 画展布置F. 水质检测G. 生产车间H. 装修报价 正文 总共10道题。 A. 移动距离…

云原生--基础篇-2--云计算概述(云计算是云原生的基础,IaaS、PaaS和SaaS服务模型)

1、云计算概念 云计算是一种通过互联网提供计算资源&#xff08;包括服务器、存储、数据库、网络、软件等&#xff09;和服务的技术模式。用户无需拥有和维护物理硬件&#xff0c;而是可以根据需要租用这些资源&#xff0c;并按使用量付费。 2、云计算特点 &#xff08;1&am…