【C++】list的介绍及使用说明

目录

00.引言

01.list的介绍

模版类

独立节点存储

list的使用

1.构造函数

2.迭代器的使用

分类

运用

3.容量管理

empty():

size():

4.元素访问

5.增删查改


00.引言

我们学习数据结构时,学过两个基本的数据结构:顺序表链表顺序表中的数据是连续存储的,并且支持随机访问,但是增删数据的效率比较低,因为要挪动数据;链表中的数据是分散存储的,每个节点包含一个数据和指向令一个节点的指针,不支持随机访问,但插入和删除操作的效率较高。

vector容器内部数据存储原理可以认为是顺序表,而list可以认为是双向链表(每个节点都包含指向前一个和后一个节点的指针)。

01.list的介绍

模版类

和"std::vector"一样,“std::list”实现不同类型数据的管理也是通过模版类的机制实现的。当创建一个list对象时,可以通过模版参数来指定存储的元素类型。使用"<数据类型>"来显式实例化指定存储的元素类型,例如“std::list<int>”表示存储整数类型的链表,“std::list<double>”表示存储双精度浮点型的链表……

#include <iostream>

template<typename T>
class list {
    ……
};

int main() {
    list<int> myList1;
    list<double> myList2;

    return 0;
}

独立节点存储

list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。因此list可以在任意位置进行插入和删除,且时间复杂度为O(1),并且该容器可以前后双向迭代。

list的使用

在cpluscplus网站上有具体的list的使用说文档:list使用文档,在实际运用中,需要熟悉一些常用的list接口,以下列出了一些常见接口:

1.构造函数

在使用list创建对象之前,需要包含头文件“<vector>”。

我们需要调用构造函数来创建对象,list的构造函数有以下几种:

1.list():无参构造

2.list(size_type n,const value_type& val = value_type()):初始化n个val的元素

3.list(const list& x):拷贝构造函数

4.list(inputiterator first, inputiterator last):用(first,last)区间中的元素构造

代码演示:


void text1()
{
    list<int> l1;
    list<int> l2(5, 10);
    list<int> l3(l2);
    list<int> l4(l3.begin(), l3.end());

    int arr[] = { 0,1,2,3,4 };
    list<int> l5(arr, arr + 5);
}

运行结果:

2.迭代器的使用

可以将 list 中的迭代器理解为一个指针,该指针指向list中的某一个节点

分类

    · begin + end:返回第一个数据位置的迭代器 + 返回最后一个数据的下一个位置的迭代器

    · rbegin + rend:返回第一个元素的reverse_iterator,即end位置 + 返回最后一个元素下一个位置的reverse_iterator,即begin位置

注意:

1.begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

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

运用

遍历list只能用迭代器和范围for,而vector还可以用类似与数组的下标[]访问,那是因为vector中的数据是连续存储的,而list中是分散存储的,元素地址直接并无关联。

迭代器和范围for遍历:


void text2(const list<int>& l)
{
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it) {
        cout << *it << " ";
        //*it = 10; 编译不通过
    }
    cout << endl;
}
int main() {
    //text1();
    list<int> l{ 1,2,3,4,5,6,7,8,9 };
    text2(l);
    return 0;
}

运行结果: 

可以看到这里使用的是const迭代器,这表示迭代器指向的元素是不可被修改的,来看看const_iterator的底层是这样定义的:

class list {
public:
    // other members...

    // 内部定义 const_iterator
    typedef const T* const_iterator;
};

所以const迭代器指向的元素是常量,不可进行修改操作,而迭代器本身是可以++或--的,如果是

typedef T* const const_iterator;

这种方式定义,则表示迭代器本身不可++或--操作,其指向的元素则可以被修改。

正向反向迭代器:


void text3()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    // 使用正向迭代器正向list中的元素
    // list<int>::iterator it = l.begin();   // C++98中语法
    auto it = l.begin();                     // C++11之后推荐写法
    while (it != l.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 使用反向迭代器逆向打印list中的元素
    // list<int>::reverse_iterator rit = l.rbegin();
    auto rit = l.rbegin();
    while (rit != l.rend())
    {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}

int main() {
    text3();
    return 0;
}

运行结果: 

在C++11中引入了auto关键字,编译器会自动推导auto定义的变量的类型,具体内容可以参考我的这篇博客:auto关键字与基于范围的for循环(C++11)

3.容量管理

list虽然不需要动态开辟管理内存空间,但是还是要对节点的数量(数据的个数)进行跟踪管理

empty():

用于检查列表是否为空。如果列表为空,则返回 ‘true’,否则返回 ‘false’。

代码演示:


void text4()
{
    list<int> myList;
    if (myList.empty()) {
        std::cout << "List is empty!" << std::endl;
    }
    else {
        std::cout << "List is not empty. Size: " << myList.size() << std::endl;
    }

}

int main() {
    text4();
    return 0;
}

 运行结果:

size():

用于获取列表中的数量。

代码演示:


void text5()
{
    list<int> myList = { 1, 2, 3, 4, 5 };
    std::cout << "Size of list: " << myList.size() << std::endl;
}

int main() {
    text5();
    return 0;
}

运行结果:

4.元素访问

有别与begin、end,list中可以通过front、back函数分别获取list的第一个节点的引用和最后一个节点的引用,是直接获取元素本身,而不是元素地址(指向元素的迭代器(指针))。

代码演示:

void text6()
{
    list<int> myList = { 1, 2, 3, 4, 5 };
    int firstElement = myList.front();
    cout << "First element: " << firstElement << endl;
    int lastElement = myList.back();
    cout << "Last element: " << lastElement << endl;

}

int main() {
    text6();
    return 0;
}

5.增删查改

下面是代码演示:


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;
}

// list插入和删除
// push_back/pop_back/push_front/pop_front
void Test1()
{
    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);
    PrintList(L);

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    PrintList(L);
}

// insert /erase 
void Test2()
{
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));

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

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

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

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

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);

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

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

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

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

int main() {
    Test1();
    Test2();
    Test3();
    return 0;
}

运行结果: 

以上就是关于list的介绍和使用说明的有关知识了,欢迎在评论区留言~感觉这篇博客对您有帮助的可以点赞关注支持一波喔~😉 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为机考入门python3--(16)牛客16-购物单最大满意度

分类&#xff1a;动态规划&#xff0c;组合&#xff0c;最大值&#xff0c;装箱问题 知识点&#xff1a; 生成递减数 100, 90, 80, ..., 0 range(100, -1, -10) 访问列表的下标key for key, value in enumerate(my_list): 动态规划-捆绑装箱问题 a. 把有捆绑约束的物…

【技术变现之道】如何打造IT行业的超级个体?

前言 在当今的数字化时代&#xff0c;IT行业蓬勃发展&#xff0c;为具备技术专长的个人提供了无限的可能性。想要成为IT行业的超级个体&#xff0c;实现知识与技能的变现吗&#xff1f;以下是一些高效途径&#xff0c;助你一臂之力&#xff01; 1. 独立接单外包 1&#xff09…

Flask项目在Pycharm中设置局域网访问

打开PyCharm导入本应用。点击Run标签中的Edit Configurations 其中Target type选择Script path&#xff0c;Target填入本项目中app.py的路径&#xff0c;Additional optional填入--host0.0.0.0(不要有空格)。 再重新运行项目&#xff0c;会观察到除了原本的http://127.0.0.1:50…

上线流程及操作

上节回顾 1 搜索功能-前端&#xff1a;搜索框&#xff0c;搜索结果页面-后端&#xff1a;一种类型课程-APIResponse(actual_courseres.data.get(results),free_course[],light_course[])-搜索&#xff0c;如果数据量很大&#xff0c;直接使用mysql&#xff0c;效率非常低--》E…

分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测

分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量…

FebHost:注册.CA域名的企业有什么限制?

在加拿大&#xff0c;只要满足加拿大互联网注册管理局的“加拿大注册要求”&#xff0c;任何类型的企业都可以注册.CA域名。这些要求的目的是为了确保.CA域名空间作为一个重要的公共资源得到合理的使用和开发&#xff0c;以促进所有加拿大人的社会和经济发展。 以下是一些主要…

0418WeCross搭建 + Caliper测试TPS

1. 基本信息 虚拟机名称&#xff1a;Pure-Ununtu18.04 WeCross位置&#xff1a;/root/wecross-demo 2. 搭建并启动WeCross 参考官方指导文档 https://wecross.readthedocs.io/zh-cn/v1.2.0/docs/tutorial/demo/demo.html 访问WeCross网页管理平台 http://localhost:8250/s/…

嵌入式科普(15)小米su7成本分析和拆解之智驶、座舱分析

目录 一、概述 二、小米su7成本分析 2.1 整车成本构成 2.2 三电系统 2.3 车身与底盘 2.3 智能网联 2.4 内外饰 三、小米su7拆解之智驶、座舱分析 3.1 主要芯片 3.2 智能驾驶&智能座舱 四、NXP S32K324汽车通用微控制器 嵌入式科普(15)小米su7成本分析和拆解之智…

问答营销之官方号问答推广技巧

问答营销作为一种网络推广的重要手段&#xff0c;受到各大品牌企业的关注。实战中&#xff0c;问答营销有新起提问再回答和直接回复老问题两种形式&#xff0c;一般做企业官方号问答营销都是选择后者。这里小马识途营销顾问详细解析下开展老问题回复营销的思路和步骤。 一、分析…

2024最新大厂C++面试真题合集,玩转互联网公司面试!

小米C 1. 进程和线程的区别 进程是操作系统分配资源和调度的独立单位&#xff0c;拥有自己的地址空间和系统资源。线程是进程内部的执行单元&#xff0c;共享属于相同进程的资源&#xff0c;但是执行切换代价更小。进程间相互独立&#xff0c;稳定性较高&#xff1b;线程间共…

C++修炼之路之反向迭代器和非模板参数,模板特化,分离编译

目录 前言 一&#xff1a;反向迭代器 二&#xff1a;非类型模板参数 三&#xff1a;模板的特化 四&#xff1a;模板的分离编译 五&#xff1a;模板的优点与缺点 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 前言 在vector&am…

代码随想录第40天|343. 整数拆分

343. 整数拆分 343. 整数拆分 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 动态规划&#xff0c;本题关键在于理解递推公式&#xff01;| LeetCode&#xff1a;343. 整数拆分_哔哩哔哩_bilibili 给定一个正整数 n &#xff0c;将其拆分为 k 个 正…

2024-4-18 群讨论:Java Agent,JFR 与 JIT 的一些讨论

以下来自本人拉的一个关于 Java 技术的讨论群。关注公众号&#xff1a;hashcon&#xff0c;私信进群拉你 命令行中带 -XX:StartFlightRecording 启动&#xff0c;同时带 -javaagent&#xff0c;那么谁先启动&#xff1f;jfr能采集到agent启动前后资源消耗情况不&#xff1f; 不…

基于深度学习的手写汉字识别系统(含PyQt+代码+训练数据集)

基于深度学习的手写汉字识别系统&#xff08;含PyQt代码训练数据集&#xff09; 前言一、数据集1.1 数据集介绍1.2 数据预处理 二、模型搭建三、训练与测试3.1 模型训练3.2 模型测试 四、PyQt界面实现参考资料 前言 本项目是基于深度学习网络模型的人脸表情识别系统&#xff0…

c++编程(6)——类与对象(4)运算符重载、赋值重载函数

欢迎来到博主的专栏——C编程 博主ID&#xff1a;代码小豪 文章目录 运算符重载赋值重载函数默认赋值重载函数其他运算符重载函数 运算符重载 重载这个概念在c中已经出现两次了&#xff0c;在前面的文章中&#xff0c;函数重载指的是可以用相同名字的函数实现不同的功能。而运…

【WebSocket连接异常】前端使用WebSocket子协议传递token时,Java后端的正确打开方式!!!

文章目录 1. 背景2. 代码实现和异常发现3. 解决异常3.1 从 URL入手3.2 从 WebSocket子协议的使用方式入手&#xff08;真正原因&#xff09; 4. 总结&#xff08;仍然存在的问题&#xff09; 前言&#xff1a; 本篇文章记录的是使用WebSocket进行双向通信时踩过的坑&#xff0c…

将gdip-yolo集成到yolov9模型项目中(支持预训练的yolov9模型)

1、yolov9模型概述 1.1 yolov9 YOLOv9意味着实时目标检测的重大进步&#xff0c;引入了可编程梯度信息&#xff08;PGI&#xff09;和通用高效层聚合网络&#xff08;GELAN&#xff09;等开创性技术。该模型在效率、准确性和适应性方面取得了显著改进&#xff0c;在MS COCO数…

「 安全工具介绍 」软件成分分析工具Black Duck,业界排名TOP 1的SCA工具

在现代的 DevOps 或 DevSecOps 环境中&#xff0c;SCA 激发了“左移”范式的采用。提早进行持续的 SCA 测试&#xff0c;使开发人员和安全团队能够在不影响安全性和质量的情况下提高生产力。前期在博文《「 网络安全常用术语解读 」软件成分分析SCA详解&#xff1a;从发展背景到…

Qt-饼图示范

1.效果图 2.代码如下 2.1 .h文件 #ifndef PIECHARTWIDGET_H #define PIECHARTWIDGET_H#include <QWidget> #include <QChartView> #include <QPieSeries>#include<QVBoxLayout> #include<QMessageBox> #include <QtCharts>struct PieDat…

FastAPI - uvicorn设置 logger 日志格式

怎么将日志打印到文件 在main.py加入log_config“./uvicorn_config.json” import uvicornif __name__ "__main__":uvicorn.run("app:app", host"0.0.0.0", port8000, log_config"./uvicorn_config.json")uvicorn_config.json {&qu…
最新文章