list和vector容器的插入与访问操作区别

news2024/11/27 12:45:40

文章目录

    • list插入元素和vector插入元素对比案例
      • vector的做法
      • list优化的做法
      • 为什么时间复杂度相同还会有性能差异

std::liststd::vector是C++中的两种常见数据结构,它们在不同的使用场景下各有优势。

  • std::vector的内部实现是动态数组,它在连续的内存块中存储数据。这使得std::vector访问元素时具有非常高的效率,因为可以直接通过索引来访问元素,时间复杂度为O(1)。然而,std::vector在插入和删除元素时可能需要移动大量的元素,特别是在非尾部进行插入或删除操作时,时间复杂度为O(n)
  • std::list的内部实现是双向链表,它在非连续的内存块中存储数据。这使得std::list插入和删除元素时具有非常高的效率,因为你只需要修改相关节点的指针,无需移动其他元素时间复杂度为O(1)。然而,std::list在访问元素时可能需要遍历整个链表,时间复杂度为O(n)

如果主要的操作是插入元素insert操作,那么使用std::list会比使用std::vector更高效。

list插入元素和vector插入元素对比案例

leetcode406.根据身高重建队列

vector的做法

class Solution {
public:
    //注意cmp接收的是两个一维数组,而不是二维数组
    static bool cmp(vector<int>& P1,vector<int>& P2){
        if(P1[0]>P2[0])  return true;//整体降序
        if(P1[0]==P2[0]){
            if(P1[1]<P2[1]) 
                return true;//p1[0]相同的时候按照p1[1]升序
        }
        return false;
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        //先对所有的hi降序排序,因为本题的people中的变量是{a,b},所以需要自定义sort cmp
        sort(people.begin(),people.end(),cmp);
        //定义新的二维数组作为输出
        vector<vector<int>>result;
        //开始遍历排序后的people
        for(int i=0;i<people.size();i++){
            //因为此时已经排序完毕,所以[6,1]直接插入到下标为1的地方,[5,0]直接插入下标为0的地方
            int position=people[i][1];//people[i][1]就代表着第i个集合people的第二个元素!
            //元素放到对应的二维结果数组里
            result.insert(result.begin()+position,people[i]);
        }
        return result;

    }
};

在这里插入图片描述

list优化的做法

class Solution {
public:
    static bool cmp(vector<int>& P1,vector<int>& P2){
        if(P1[0]>P2[0])  return true;
        if(P1[0]==P2[0]){
            if(P1[1]<P2[1]) 
                return true;
        }
        return false;
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(),people.end(),cmp);
        //结果数组类型修改为list<vector<int>>
        list<vector<int>>result;
        
        //遍历排序后的people
        for(int i=0;i<people.size();i++){
            int position=people[i][1];
            //找到position位置之后,定义迭代器再插入
            list<vector<int>>::iterator it = result.begin();
            //注意这里insert的写法,先寻找插入位置
            while(position--){
                it++;
            }
            //while结束之后找到插入位置
            result.insert(it,people[i]);
        }
        //把结果转换为vector<vector<int>>,相当于构造新的二维vector
        return vector<vector<int>>(result.begin(),result.end());

    }
};

在这里插入图片描述
其直观上来看数组的insert操作是O(n)的,整体代码的时间复杂度是O(n^2)。
链表的insert查找+插入也是O(n),整体代码时间复杂度是一样的。

为什么时间复杂度相同还会有性能差异

对于普通数组,一旦定义了大小就不能改变,例如int a[10];,这个数组a至多只能放10个元素,改不了的。

对于动态数组,就是可以不用关心初始时候的大小,可以随意往里放数据,那么耗时的原因就在于动态数组的底层实现

那么动态数组为什么可以不受初始大小的限制,可以随意push_back数据呢?

首先vector的底层实现也是普通数组

vector的大小有两个维度一个是size一个是capicity,size就是我们平时用来遍历vector时候用的,例如:

for (int i = 0; i < vec.size(); i++) {

}

capicity是vector底层数组(就是普通数组)的大小,capicity不一定=size

当insert数据的时候,如果已经大于capicity,capicity会成倍扩容,但对外暴漏的size其实仅仅是+1

那么既然vector底层实现是普通数组,怎么扩容的?

就是重新申请一个二倍于原数组大小的数组,然后把数据都拷贝过去,并释放原数组内存

举一个例子,如图:
在这里插入图片描述
原vector中的size和capicity相同都是3,初始化为1 2 3,此时要push_back一个元素4。

那么底层其实就要申请一个大小为6的普通数组,并且把原元素拷贝过去,释放原数组内存,注意图中底层数组的内存起始地址已经变了。

同时也注意此时capicity和size的变化,是成倍改变的!

而在本案例中,我们使用vector来做insert的操作,此时大家可会发现,虽然表面上复杂度是O(n2),但是,其底层都不知道额外做了多少次全量拷贝了,所以算上vector的底层拷贝,整体时间复杂度可以认为是O(n^2 + t × n)级别的,t是底层拷贝的次数

所以,虽然插入操作的理论时间复杂度没有改变,但 在实践中,由于std::list不需要移动元素,所以实际运行时间会更短。这就是为什么使用std::list后代码运行时间减少的原因。

参考:
代码随想录-vector和list差别解释

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

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

相关文章

weak_ptr 智能指针的使用

目录 一&#xff0c;weak_ptr 变量的定义 二&#xff0c;expired() 成员函数 三&#xff0c;lock() 成员函数 四&#xff0c;use_count() 成员函数 五&#xff0c;为什么要用 weak_ptr 一&#xff0c;weak_ptr 变量的定义 weak_ptr 对象的构造有3种方法&#xff1a; 1&am…

Python基础综合案例-数据可视化(折线图)

今天给大家带来的是Python综合实战开发的数据可视化操作 通过python实现对数据的分析、可视化 数据来源: 系统开发环境&#xff1a; 操作系统&#xff1a;win11 Python解释器版本&#xff1a;python3.10 开发工具&#xff1a;Pychram Python内置模块&#xff1a;pyecharts 1…

HarmonyOS/OpenHarmony应用开发-Stage模型应用/组件级配置

在开发应用时&#xff0c;需要配置应用的一些标签&#xff0c;例如应用的包名、图标等标识特征的属性。本文描述了在开发应用需要配置的一些关键标签。图标和标签通常一起配置&#xff0c;可以分为应用图标、应用标签和入口图标、入口标签&#xff0c;分别对应app.json5配置文件…

二进制算术运算

当两个数码表示数量大小时&#xff0c;可以进行加减乘除等算术运算。 一&#xff1a;两数绝对值之间的运算 加法运算&#xff1a; 二进制的每一位只有0和1两个数&#xff0c;低位向高位的进位关系是“逢二进一”&#xff0c;所以中的每一位的运算规则为&#xff1a; 减法运算&…

【无标题】企业数字化转型需要什么样的生产力工具?

前言 企业的数字化转型是一个很大的话题&#xff0c;从宏观到微观&#xff0c;涉及到目标、战略、方案、路径、计划、组织、流程等方方面面。我们今天聊一个非常落地非常具体的问题——企业数字化转型需要什么样的生产力工具&#xff1f; 需要哪些类型的生产力工具&#xff1…

论文摘要写什么内容

一、引言 论文摘要是我们在学术研究领域当中最常见的一种形式&#xff0c;它扮演着关键的角色&#xff0c;为研究者在学术圈子中传播自己思想提供了重要途径。然而&#xff0c;如何编写一份既简洁而易读&#xff0c;又充满深度和洞察的摘要呢&#xff1f;这篇文章将提供一些基…

Scala特证/特质【6.7 特质(Trait)】

Scala特证/特质【6.7 特质&#xff08;Trait&#xff09;】 6.7 特质&#xff08;Trait&#xff09;Java 的接口接口的作用抽象类的作用 6.7.1 特质声明6.7.2 特质基本语法6.7.3 特质叠加6.7.4 特质叠加执行顺序6.7.5 特质自身类型6.7.6 特质和抽象类的区别 &#xff08;任意内…

Lua学习笔记:面向对象的实现

前言 本篇在讲什么 Lua中的面向对象的实现 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Sublime Text编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全流程的源码内容 ★提高阅读体验★ &…

MySQL数据库基础(三):多表查询,子查询,开窗函数

十一、多表查询&#xff08;重点、难点&#xff09; 表与表之间的关系 在SQL语句中&#xff0c;数据表与数据表之间&#xff0c;如果存在关系&#xff0c;一般一共有3种情况&#xff1a; ① 一对一关系&#xff08;高级&#xff09; 比如有A、B两张表&#xff0c;A表中的每一…

多肽试剂:143120-27-8,Cyclo(-D-Tyr-Arg-Gly-Asp-Cys(carboxymethyl)-OH) sulfoxide

试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a; 环肽试剂Cyclo(-D-Tyr-Arg-Gly-Asp-Cys(carboxymethyl)-OH) sulfoxide&#xff0c;陕西新研博美生物科技有限公司多肽合成、定制多肽、同位素标记肽、人工胰岛素、磷酸肽、生物素…

Python split()函数使用详解,Python分割字符串

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 split 1、不指定分隔符2、分隔符的类型3、指定分隔次数4、分隔的结果 split() 可…

你真的不想知道怎么用ai绘画图片生成图片吗?

亲爱的二次元迷们&#xff0c;你是否曾经梦想过能够画出自己心中的二次元角色&#xff0c;让他们跃然纸上、生动活泼地展现在世人面前&#xff1f;但是&#xff0c;面对空白的画板和一支笔&#xff0c;我们有时会感到无从下手&#xff0c;毫无艺术细胞可言。不要失望&#xff0…

Dlib —— 对视频流进行人脸识别(附C++部分源码、完整源码下载)

照片效果 视频效果 注意&#xff1a;Dlib检测人脸在Release版耗时与CPU有关,本人I7 10代约100ms左右&#xff0c;这里本人将人脸检测用Yolov5对人脸简单抠图训练后 使用yolov5推理检测人脸&#xff0c;之后将检测到的人脸输入给Dlib做特征&#xff0c;发现人脸特征部分耗时也较…

基础实验篇 | uORB消息读写与自定义实验(一)

导读 uORB是PX4/Pixhawk系统中非常重要且关键的模块之一&#xff0c;是用于无人机模块间通信的协议机制。本篇将详细介绍uORB并详细拆解uORB消息读写与自定义实验&#xff08;一&#xff09;。 基础实验篇 | uORB消息读写与自定义实验(一) ect Request Broker&#xff0c;微对…

7、动手学深度学习——卷积神经网络:基础部件+LeNet

1、图像卷积 1. 互相关运算 严格来说&#xff0c;卷积层是个错误的叫法&#xff0c;因为它所表达的运算其实是互相关运算&#xff08;cross-correlation&#xff09;&#xff0c;而不是卷积运算。在卷积层中&#xff0c;输入张量和核张量通过(互相关运算)产生输出张量。 首先…

python 中禁用 SettingWithCopyWarning

最近代码中出现了这个warn&#xff0c;但是我确信我已经把所有的df赋值都改成loc了&#xff0c;依旧会出现&#xff0c;只有把这个warn禁了。 import pandas as pd import warnings# 禁用 SettingWithCopyWarning 警告 warnings.filterwarnings("ignore", categorypd…

闲人闲谈PS之四十三——标准程序的陷阱

惯例闲话&#xff1a;7月&#xff0c;闲人家乡的水蜜桃成熟了&#xff0c;闲人很喜欢吃桃子&#xff0c;可惜经常出门在外&#xff0c;经常错过了水果最好的季节&#xff0c;这次委托家人邮寄了几箱&#xff0c;果然还是家乡的桃子好吃。回顾这几年&#xff0c;错过了不仅仅是水…

数据库sql 根据身份证计算年龄段mysql、oracle

数据库sql根据身份证计算年龄段 mysql: SELECTage,count(*) numFROM(SELECTCASEWHEN TIMESTAMPDIFF(YEAR,DATE(substring(id_card,7,8)),CURDATE())<35 THEN 35岁以下WHEN TIMESTAMPDIFF(YEAR,DATE(substring(id_card,7,8)),CURDATE()) > 35AND TIMESTAMPDIFF(YEAR,DATE…

deque容器语法

文章目录 deque容器deque容器基本概念功能&#xff1a;deque 的实现细节deque与vector底层区别&#xff1a; deque构造函数功能描述&#xff1a;函数原型&#xff1a; deque元素访问deque赋值操作功能描述&#xff1a;函数原型&#xff1a; deque大小操作功能描述&#xff1a;函…

哪些期货公司招居间人,期货居间人的红利期时代已过,该何去何从

2021年9月10日&#xff0c;中国期货业协会发布了关于发布《期货公司居间人管理办法 (试行)》的通知&#xff0c;《期货公司居间人管理办法(试行)》正式出台。 根据通知&#xff0c;期货公司仅能与经有关金融监管部门批准设立的证券公司等金融机构开展居间合作。现在的法人居间绝…