STL库(1)

news2024/11/23 18:36:41

STL库(1)

  • vector
    • vector介绍
    • vector使用
      • 初始化
      • 元素访问
      • 内存扩容
      • 插入删除
  • list
    • list介绍
    • 初始化,元素访问
    • 插入
    • 删除元素
  • vector和list区别

vector

vector介绍

  • vector是可以改变大小的数组的容器。
  • 其内存结构和数组一样,使用连续的存储空间,也就可以使用指针指向其元素,通过偏移量来访问存储空间中的元素。
  • 和数组不同之处在于vector的大小可以动态的变化,容器可以自动扩容存储空间。
  • vector使用一个动态分配的连续存储空间来存储元素,在插入新元素的时候也可能需要重新分配存储空间,也就意味着每次扩容都需要将其元素重新移动到新的存储空间中,很显然这效率是非常低的,为此不会每次像容器中添加元素都重新分配。
  • 容器可以分配一些额外的存储空间以适应添加的对象,其每次扩容以原本的1.5或2倍来扩容。
  • 与其他的容器相比,vector可以更加高效的访问其他元素,并且可以高效的从尾部添加或者删除元素。对于节位意外的位置插入删除效率较低。

vector使用

初始化

int main() {
	vector<int> iar;
	vector<double> dar(12,10,0);
	vector<int> ibr={1,2,3,4,5,6};
	vector<Int> Iar;//处理自定义类型
	vector<int*>par;//尽量别这么使用,因为其可能指向动态申请的内存,其不会主动释放。
}

元素访问

1.at访问(返回的是引用,可以进行修改)
2.下标访问
3.data()返回首地址,通过首地址偏移量进行解引用操作。
4.迭代器
5.范围for

int main() {
	vector<int> iar={1,2,3,4,5};
	int n=iar.size();
	for(int i=0;i<n;i++) {
		ibr.at(i)+=10;
		cout<<iar.at(i)<<" "<<iar[i]<<endl;
	}
	cout<<iar.back()<<endl;
	cout<<iar.front()<<endl
	int* p=ibr.data();
	for(int i=0;i<n;++i) {
		cout<<p[i]<<endl;
		//*(p+i);
	}
	for(auto &x:iar) {
		cout<<x<<" ";
	}
	vector<int>::iterator it=iar.begin();
	vector<int>::const_iterator cit=iar.begin();
	vector<int>::reverse_iterator rit=iar.rbegin();//逆向迭代器
	for(;rit!=rend();) {
		cout<<*rit<<endl;
	}
	vector<int>::const_reverse_iterator it=iar.rbegin();
	for(;it!=iar.end();){
		(*it)-=100;
		cout<<*it<<endl;
	}
}

内存扩容

int main() {
vector<int> var ;
    for (int i = 0; i < 100; i++) {
        var.push_back(i);
        cout << "size:" << var.size() << endl;;
        cout << "capacity:" << var.capacity() << endl;
    }
}

运行上面代码我们观察输出结果:
其容量分别是:1,2,3,4,6,9,13,19…其扩容分别按照原本的1.5倍扩容,如果其1.5倍和原本一样就对容量进行+1操作。
这里我们用的是内置类型,如果是我们自己定义的类呢,就会发生这样的过程,比如我们定义的是ptr类,类中存在构造,拷贝构造,移动构造,移动赋值,析构等函数此处不做编写。
扩容等操作我们来具体理解以下:

int main() {
	std::vector<Ptr> ar;
	for(int i=0;i<100;i++) {
		ar.push_back(Ptr(i));
		cout << "size:" << ar.size() << endl;;
        cout << "capacity:" << ar.capacity() << endl;
	}
}

在这里插入图片描述
首先观察第一张图,容量为1,大小为1,在首先会调用缺省构造函数来构造ptr的无名对象,其为右值,然后使用移动构造来将无名对象的资源移动到新的对象中,该对象就存在于容器中,然后析构无名对象。紧接着当再次添加对象的时候需要进行扩容处理,其扩容就是重新申请一块内存,将原本内存中的资源拷贝一份放入新的内存中,然后释放旧的资源。为此我们可以看到其调用拷贝构造函数,创建新对象来放入新内存中,然后析构掉原本的对象,然后创建新添加的对象,移动构造来移动无名对象的资源,最后析构无名对象。这就是其扩容的内部操作。很明显效率很低,在不断的构建对象和析构对象。

为此呢我们可以使用reserve()函数。

int main() {
	std::vector<Ptr> ar;
	ar.reserve(200);
	//ar.resize(200);
	//ar.assign(10,Ptr(10));
	for(int i=0;i<100;i++) {
		ar.push_back(Ptr(i));
		cout << "size:" << ar.size() << endl;;
        cout << "capacity:" << ar.capacity() << endl;
	}
}

该函数可以直接申请够200个对象的内存,不会进行反复的扩容和拷贝构造,和这个函数相仿的还存在一个resize()函数,该函数与其不同之处在于,这个函数在申请内存之后会创建100个对象,为此加入对象的时候会从第100个后面进行添加。还存在一个assign()函数,该函数页会创建对新象,不过其需要指定创建的对象。

插入删除

int main() {
	std::vector<Ptr> ar;
	ar.reserve(10);
	ar.push_back(Ptr(1));
	ar.push_back(Ptr(2));
	ar.push_back(Ptr(3));
	ar.push_back(Ptr(4));
	ar.push_back(Ptr(5));
	vector<Ptr>::operator it=ar.begin();
	ar.insert(it,Ptr(6));
	for(auto &x:ar){
		x.Print();
	}
	ar.pop_back();
}

很明显vector的插入删除一般都是在尾部插入删除,而通过迭代器和插入函数头部插入时,必然将后面所有的元素都要向后移动,效率大幅度降低,当我们使用了迭代器之后然后尾删的时候很明显出现了程序崩掉的现象,这是为什么呢?因为我们对迭代器进行操作之后迭代器失效了。为什么会失效呢?迭代器实际上是和对象绑定的,
在这里插入图片描述
我们的迭代器是和对象绑定的,例如迭代器此时指向首元素1,然后进行了头删,那么头结点内存释放了,对象丢失了为此迭代器也就丢失了。而扩容依然是如此,重新申请了内存,拷贝了资源,那么原本的对象就丢失了,迭代器也就丢失了。

list

list介绍

  • list是序列容器,允许在序列中任何位置执行O(1)时间的插入和删除,并在两个方向上进行迭代。
  • 其底层结构是双链表,将每个元素存储在不同的存储位置,每个结点通过next,prev指针连结成的顺序表。
  • list与其他容器相比,可以在任何位置插入和删除,获得迭代器的情况下时间复杂度为O(1).
  • 不能通过下标访问,需要通过迭代器找到位置才可以访问,需要遍历的时间开销。
  • 存储密度低,使用一些额外的内存空间(next,prev指针)来保持每个元素的关联性,从而导致存储小元素的列表存储密度低。

初始化,元素访问

数组初始化,范围for遍历

int main() {
	std::list<int> arlist={1,2,3,4,5,6,7,8};
	cout<<arlist.back()<<endl
	cout<<arlist.front()<<endl;
	for(auto& x:arlist) {
		cout<<x<<" ";	
	}
}

插入

int main() {
	std::list<Ptr> arlist;
	for(int i=0;i<5;i++) {
		//arlist.push_back(Ptr(i));
		arlist.emplace_back(i);
	}
	for(const auto &x:arlist) {
		x.Print();	
	}
}

因为其list容器结构是双链表结构,所以我们进行头插尾插的效率都是一样的,不过push_back插入我们知道是先创建对象,然后进行移动构造来插入数据,效率较低,为此在list中存在emplace_back函数,他和push_back不同之处在于他是原位构造,直接在申请的内存上构造对象,不会进行移动构造然后析构对象。范围for遍历时也最好用常引用,如果不是引用便会调用拷贝构造构造对象来调用Print函数输出,使用引用就可以不在调用拷贝构造函数,大大节省了时间和空间。而加入const可以保证容器中的元素不发生改变。
同vector一样,也list容器中最好不要使用指针,为什么呢?

int main() {
	std::list<Ptr*> arlist;
	for(int i=0;i<5;i++) {
		//arlist.push_back(Ptr(i));
		arlist.emplace_back(new Ptr(i));
	}
	for(const auto &x:arlist) {
		x->Print();	
	}
}

我们使用上面代码的时候很明显其没有析构对象,因为容器中是指针,其不能判断内部是不是动态申请了内存而释放他,所以呢就不会进行析构,为此最好不要使用指针,要析构就要在范围for中使用delete析构。或者使用智能指针。

删除元素

  • erase():删除指定位置的元素,也可以删除某个区间的多个元素。
  • clear():删除所有元素。
  • remove(val):删除所有等于val的元素。
  • unique():删除容器中相邻的重复元素。
int main() {
	list<int> ilist={1,2,3,4,5,1,2,3,4,5};
	ilist.sort();
	ilist.unique();
	for(auto &x :ilist) {
		cout<<x<<" ";
	}
}

unique()删除通过上面代码就可以展示出来。
list中的sort排序底层是快排,而当数据量足够大的时候呢就会存在一个阈值,高于这个值就会使用归并排序。

vector和list区别

vectorlist
底层实现连续存储的容器,动态数组,对上分配空间动态双向链表,堆上分配空间
空间利用率连续空间,不易造成内存碎片化,空间利用率高节点不连续,容易造成内存碎片化,小元素使结点密度低,空间利用率低
查找元素下标,at,find,binary_search()find O(n)
插入push_back(val);O(1)//空间足够O(1)
迭代器随机迭代器,检查越界,支持++,–,==,+=,…双向迭代器,检查越界,支持++,–,==,!=
迭代器失效插入删除都会导致迭代失效插入元素不会导致迭代器失效,删除会导致迭代器失效,不影响其他迭代器

两者适用情况:

  • 需要高效得随机存储,不在乎插入删除效率(很少使用插入删除),选用vector
  • 需要大量得插入删除,苏哦系取值很少使用,选用list。

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

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

相关文章

我是如何精通软件工程的

软件工程是一个庞大且不断演化的领域&#xff0c;涉及许多创新。虽然如此&#xff0c;大多数技术 —— 如果不是全部 —— 在软件工程中往往最终汇聚为几个基本原则。工程师更好地掌握软件工程的方法是熟悉软件工程的基础知识&#xff0c;而不是那些不断变化的框架、语言或平台…

2023年Web服务器基准测试:NodeJS vs Java vs Rust vs Go

现在是2023年&#xff0c;是时候进行一次新的Web服务器基准测试了&#xff01; 结果对我来说有些出乎意料&#xff01; 一个Web服务器必须能够处理大量请求&#xff0c;尽管瓶颈在于IO。这次我决定比较最流行的、速度极快的现代框架的性能。 以下是有关实现细节的许多详细信息…

安装 vue-element-admin,安装报错解决

安装 vue-element-admin 克隆项目 git clone https://github.com/PanJiaChen/vue-element-admin.git //(英文的)git clone -b i18n https://github.com/PanJiaChen/vue-element-admin.git // 这个克隆出来是有中英文切换的进入项目目录 cd vue-element-admin建议不要用 cnpm…

chatgpt赋能python:Python交互编程入门指南

Python交互编程入门指南 Python是一种高级编程语言&#xff0c;适合初学者和专业人士使用。Python的互动式编程方式为开发人员提供了快速反馈的环境&#xff0c;从而实现更便捷和高效的开发过程。在本文中&#xff0c;我们将介绍Python的交互编程&#xff0c;为您提供Python编…

达梦数据库运维常用归档、sql日志、dexp与dimp操作

目录 一、归档文件配置... 3 二、sql⽇志的开启和关闭以及基本的操作... 3 三、执行计划... 5 四、工具和命令行数据库物理、逻辑备份&#xff0c;还原... 6 1、工具物理备份... 6 2、命令行联机备份... 8 3、命令行脱机备份... 8 4、工具物理还原... 8 5、命令行DMRM…

C++之动态分配new 删除delete 初始化memset

文章目录 1.动态分配 new1.引言2.new的实现 2.删除 delete3.初始化 memset 1.动态分配 new 1.引言 用new创建数组的优势&#xff1a;由于new创建的对象是在运行时确立的&#xff0c;所以有着具体情况具体分析的优点&#xff0c;那么什么叫做具体情况具体分析呢&#xff1f; 举…

linux led 驱动

前言 今天是儿童节&#xff0c;挣个奖牌给小孩玩玩。 在 linux 驱动大家庭中&#xff0c;LED 驱动算是个儿童&#xff0c;今天就写写他吧。正好之前写过他的婴儿时期《i.MX6ULL 裸机点亮 LED》&#xff0c;记得那时候他还穿着开裆裤呢&#xff0c;裸鸡嘛。 ioremap() 裸机程…

某点资讯Signature纯算逆向

本篇主要是介绍一些工作的运用熟练性&#xff0c;以及跟踪堆栈去看是否做一些其他操作等&#xff1a; 抓包: signature 为加密值&#xff1b; 先上trace下堆栈及加密 我们把结果base64下&#xff0c;看结果是否一致&#xff0c;来判断base64是否魔改 验证base64为标准&…

新规之下产业园区如何合理收费水电费用

一、政策背景 2018年3月30日&#xff0c;国家发改委发布《国家发展改革委关于降低一般工商业电价有关事项的通知》。明确提出进一步规范和降低电网环节收费&#xff0c;一是提高两部制电价的灵活性&#xff1b;二是全面清理规范电网企业在输配电价之外的收费项目&#xff0c;重…

三极管 场效应管

NPN 高电平导通 PNP 低电平导通 N-MOS 高电平导通 P-MOS 低电平导通 1. NPN 三极管&#xff0c;对于软件工程师来说&#xff0c;只需要关注数字电路&#xff0c;即: 导通还是截止&#xff0c;高电平还是低电平。至于三级管内部如何构成的&#xff0c;以及串了多少个电阻&am…

智能安全配电装置在老旧建筑防火中的应用

【摘要】现代社会的发展离不开电能&#xff0c;随着电能应用的广泛性&#xff0c;对用电安全有了更高的要求。近些年来&#xff0c;用电安全形式严峻&#xff0c;尤其是一些老旧建筑中因用电而引起的火灾事故频发&#xff0c;造成一系列严重的损失&#xff0c;严重影响着民众的…

PCout(n) -- STM32F103RCT6 位带操作

1. 使用位带操作控制GPIO口的输入、输出模式&#xff0c;以及输出的电平高、低 注&#xff1a;位带操作一般是操作单独的一个bit 位&#xff0c;而&&#xff0c;| 则可操作多个bit位&#xff0c;看自己的需求吧。&#xff08;不懂&&#xff0c;| 是什么意思的自行问度…

MySQL-6-多表操作

一、复制表 格式 create table 表名 select查询语句注意&#xff1a;复制成新表时&#xff0c;键值&#xff08;pri,index等等&#xff09;索引不会同步复制案例 mysql> create table t2 select name,sex,age from user;二、多表查询 2.1、 多表查询–>连接查询 将2个…

Vue.js 比较重要知识点总结一

概述 谈一谈你对 Vue.js 的响应式数据的理解Vue3 出现解决了什么问题&#xff1f;它有哪些优势&#xff1f;Vue3 新特性有哪些vue2 和 vue3 的响应式有什么区别&#xff1f; 谈一谈你对 Vue.js 的响应式数据的理解 Vue 2.x 对象类型&#xff1a;通过 object.defineProperty(…

MySQL——初窥门径

前言 六一&#xff1f;作为一个大小孩当然是快快乐乐搞技术啦~在这篇文章中&#xff0c;荔枝会梳理SQL语句的基本语法以及MySQL中的函数、约束。多表关系以及查询、事务和事务隔离级别等内容&#xff0c;大致内容归属于MySQL基础知识&#xff0c;荔枝又弄了一篇万字长文哈哈哈哈…

R:GAM非线性回归曲线拟合与散点密度图绘制

作者:CSDN @ _养乐多_ 本文将介绍使用R语言以及GAM模型,绘制回归曲线和散点密度图。 文章目录 一、R语言脚本二、色带一、R语言脚本 install.packages("ggpointdensity") install.packages("ggplot2") insta

IPD发展史

随着IPD&#xff08;集成产品开发&#xff09;在IBM、华为等企业取得了巨大的成功&#xff0c;其他行业也开始在相关新产品研发中初步引入IPD的研发管理理念及模式&#xff0c;对IPD在行业的应用进行初步的探索和研究。 为了更好地应用IPD &#xff0c;不仅要对它的理念和思想理…

浅谈高等学校能源监控管理体系建设

摘要&#xff1a;现代高校担当着人才培养&#xff0c;社会服务和文化传承与创新的光荣使命。高校低碳节能工作是加快建设“和谐社会”、“绿色校园”的重要举措 。当前高校以“数字化能源监测平台”为重心 &#xff0c;积极推动能源管理的转型 。该文总结高校能源监管平台建设的…

达梦数据库作业调度及警报配置

目录 作业... 4 创建代理环境... 4 1、命令行创建及删除... 4 2、客户端创建及删除... 4 操作员... 5 1、命令行创建及删除... 5 2、客户端创建及删除... 5 作业... 6 一、命令行... 6 1、命令行创建作业... 6 2、命令行修改作业... 7 3、启动或暂停作业... 7 4、…

MATLAB与深度学习:Neural Network Toolbox和Deep Learning Toolbox的使用和模型设计

章节一&#xff1a;引言 在当今人工智能和深度学习的时代&#xff0c;MATLAB作为一种功能强大的科学计算和数据分析工具&#xff0c;在深度学习领域也发挥着重要作用。本文将重点介绍MATLAB中的两个关键工具&#xff1a;Neural Network Toolbox和Deep Learning Toolbox的使用和…