【C++】STL—vector的常用接口

news2024/11/28 14:29:26

文章目录

  • 前言
  • 一、vector介绍
  • 二、vector的使用
    • 1. vector的定义
    • 2. vector的遍历
      • 2.1.operator[ ]
      • 2.2.迭代器
      • 2.3.范围for
    • 3. vector的空间增长问题
      • 3.1.size和capacity
      • 3.2.max_size和empty
      • 3.3.reserve
      • 3.4.resize
      • 3.5.Shrink to fit
    • 4. vector的增删查改
      • 4.1.push_back和pop_back
      • insert和erase
      • 4.2.find
      • 4.3.operator[]
      • 4.4.sort
      • 4.5.assign

请添加图片描述

前言

这里我们讲解vector的时候就不会像string类一样这么详细,string类讲的详解一些,为后面做铺垫。有了string类的基础,大家看一些接口就知道是什么意思,这里给大家而是讲解一些常用的接口,剩下的接口不太常用,如果大家遇到了,查文档即可,这里推荐两个C++文档,cplusplus.com 以及 cppreference.com。第二个网站是C++的官网,但是感觉不太好用,我平时都喜欢用第一个,感觉较为方便。

一、vector介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小。为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和forward_lists统一的迭代器和引用更好。

二、vector的使用

1. vector的定义

(constructor)构造函数声明接口说明
vector() 重点无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

示例:

  • vector() 无参构造
int main()
{
    vector<int> v;
}
  • vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector<int> v1(10, 5);//用10个5来初始化v1
  • vector (const vector& x); 拷贝构造
vector<int> v1(10, 1);//使用10个1来初始化v1
vector<int> v2(v1);//使用v1去拷贝构造v2
  • vector (InputIterator first, InputIterator last); 使用迭代器进行初始化构造
vector<int> v1(10, 1);//使用10个1来初始化v1
vector<int> v3(v1.begin(), v1.end());//使用迭代器拷贝构造v1的数据
  • 还可以通过迭代器初始化来获得string的字符串
string s = "hello world";
vector<char> v(s.begin(), s.end());

2. vector的遍历

接口名称使用说明
operator[ ]下标 + [ ]
迭代器begin + end 或 rbrgin + rend
范围for底层还是借用迭代器实现

2.1.operator[ ]

operator[ ]就是对[ ]的重载,我们可以像C语言那样使用下标 + [ ]去访问元素。

void test_vector1()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	
	for (size_t i = 0; i < v.size(); ++i)
	{
		cout << v[i] << "";
	}
	cout << endl;
}

2.2.迭代器

vector的迭代器和string的迭代器近乎一致,规则也都类似。

iterator的使用接口说明
begin + endbegin获取第一个数据位置的iterator/const_iterator,end获取最后一个数据的下一个位置的iterator/const_iterator
rbegin + rendrbegin获取最后一个数据位置的reverse_iterator,rend获取第一个数据前一个位置的reverse_iterator

image-20221130105612237

  • 正向迭代器:
void test()
{
    vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}
  • 反向迭代器:
void test()
{
    vector<int>::iterator it = v.rend();
    while(it != v.rbegin())
    {
        cout << *it << " ";
        it++;
	}
    cout << endl;
}

2.3.范围for

范围for的底层就是替换了迭代器,先前string类已经实现过。

void test()
{
    for(auto e : v)
	{
		cout << e << " ";  
	}
	cout << endl;
}

3. vector的空间增长问题

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize(重点)改变vector中的size
reserve(重点)改变vector的capacity
max_sizevector中的最大数据
Shrink to fit收缩字符串容量

3.1.size和capacity

vector的size是用来获取有效数据个数,而capacity就是获取容量大小:

void test_vector2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

	v.push_back(5);
	v.push_back(6);
	v.reserve(10);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	
	// 比当前容量小时,不缩容
	v.reserve(4);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
}

3.2.max_size和empty

max_size的作用是返回vector容器可以容纳的最大元素数,用类型的最大值除以sizeof(类型)即max_size。

empty是判断vector容器是否为空。

void test()
{
	vector<int> v;
	cout << v.max_size() << endl;
    v.push_back(1);
    v.push_back(1);
    v.push_back(1);
    if(empty(v))
        cout << "vector is empty" << endl;
}

3.3.reserve

reserve的作用是请求更改容量capacity。

  1. 如果 n 大于当前容量,则该函数会导致容器重新分配其存储,可能会发生异地扩容,将其容量增加到 n(或更大)。
  2. 在其他情况下,函数调用不会导致重新分配内存,即容量不会受影响。
void test()
{
    vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
    // 比当前容量大时,增容
	v.reserve(10);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
    // 比当前容量小时,不缩容
	v.reserve(4);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
}
  • 补充:
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

测试结果如下:

image-20221130152659155

  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。
  • 为什么一定要按照1.5倍或2倍增长呢?

答案:合适,单次增容越多,插入N个值,增容次数越少,效率就越高,但是浪费空间就越多。单次增容越少,就会导致频繁增容,效率低下。1.5倍或2倍是最平衡的做法。

3.4.resize

resize在空间的同时也进行了初始化。

  1. 如果 n 小于当前容器大小,则内容将减少到其前 n 个元素,删除超出(并销毁)的元素。
  2. 如果 n 大于当前容器大小 ,则通过在末尾插入所需数量的元素以达到 n 的大小来扩展内容。如果指定了 val,则新元素将初始化为 val 的副本,否则,它们将进行值初始化。
void test()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	v.resize(8);
	v.resize(15, 1);
	v.resize(3);
}

3.5.Shrink to fit

image-20221130205414883

  1. 请求容器减小其容量以适应其大小。

  2. 请求是非绑定的,容器实现可以自由优化,并使vector具有大于其大小的容量。

  3. 这可能会导致重新分配,但对vector大小没有影响,并且不能更改其元素。

void test()
{
    vector<int> v(100);
    cout << v.capacity() << " "; // 100
    str.resize(10);
    cout << v.capacity() << " "; // 100
    str.shrink_to_fit();
    cout << v.capacity() << " "; // 10
}

4. vector的增删查改

vector增删查改接口说明
push_back(重点)尾插
pop_back(重点)尾删
find查找(注意这个是算法模块实现,不是vector的成员接口)
insert在下标为pos的前面插入val
erase删除pos位置的数据
swap交换两个vector的数据空间
operator[] (重点)像数组一样访问
sort排序(注意这里也不是vector的函数接口,只是用于排序)
assign分配内容给vector,即初始化vector,覆盖原来的内容

4.1.push_back和pop_back

这俩接口和string的没啥区别,这里简单给出测试用例:

void TestBitVector2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.front() << endl;
	cout << v.back() << endl;
	cout << v[0] << endl;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.pop_back();
	v.pop_back();
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

insert和erase

insert就是在迭代器下标为pos的前面插入val,erase就是删除迭代器下标为pos的值。

void test()
{
    vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.insert(v.begin(), 0);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.erase(v.begin() + 1);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

4.2.find

这里的find并不是vector的成员函数,这个是算法模块实现。其本质就是在一段左闭右开的迭代器区间去寻找一个值。找到了就返回它的迭代器,找不到就返回它的开区间那个迭代器。

image-20221130153309055

void test()
{
    vector<int> v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30); 
	v1.insert(v1.begin(), 40);
	v1.insert(v1.begin()+2, 50);
    // 没有find成员
	//vector<int>::iterator it = v.find(3);
	vector<int>::iterator it = find(v1.begin(), v1.end(), 20);
	if (it != v1.end())
	{
		v1.insert(it, 2);
	}
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

4.3.operator[]

operator[ ]就是对[ ]的重载,我们可以像C语言那样使用下标 + [ ]去访问元素。

这里有一个经典错误,我们开辟了10个容量的空间,然后去访问,发现访问不了。这是因为你只开空间但是没有初始化。所以这里我们根本进不去for循环。我们用v[6]去访问元素,发现程序崩溃。这里我们应该用resize。

void test()
{
	vector<int> v;
	v.reserve(10); // size没有变化
	//v.resize(10);
	//v[6];
	for (size_t i = 0; i < v.size(); i++)
	{
		v[i] = i; // assert
		v.at(i) = i; // 抛异常
	}
}

我们在讲string类的时候说过,operator[]访问异常会断言报错,而at会抛异常,异常我们以后在涉及。

4.4.sort

sort函数也不是vector的成员函数,这里只是为了对vector创建的数据进行排序。

image-20221130153405360

void test()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(6);
	v.push_back(-2);
	v.push_back(23);
	v.push_back(-6);
//默认sort是升序
	sort(v.begin(), v.end());
	for (auto e : v)
		cout << e << " "; 
	cout << endl;
//要排降序,就要用到仿函数,具体是啥后续详谈
	sort(v.begin(), v.end(), greater<int>());
	for (auto e : v)
		cout << e << " "; 
}

4.5.assign

给vector重新赋值,可能会引起底层容量改变。也可以给其他容器赋值,比如string。

void test()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.assign(10, 1); // 赋值为10个1	
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v.assign(v1.begin(), v1.end());//以v1的元素赋值v
	for (auto e : v)
	{
		cout << e << " "; // 10 20 30
	}
	cout << endl;

	string s("hello world");// 这里去掉首字母h,尾字母d
	v.assign(++s.begin(), --s.end()); // 因为模板为int类型,所以string类的字符为强转为int
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

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

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

相关文章

Vue 3的高颜值UI组件库

Vue 3.0 已经发布两年多的时间&#xff0c;今年 2 月 Vue 3.0 也正式成为新的默认版本。今天就来分享 7 个适用于 Vue 3 的高颜值 UI 组件库&#xff01; Element Plus Element Plus 是一套由饿了么开源出品的为开发者、设计师和产品经理准备的基于 Vue 3.0 的组件库。Elemen…

【能源管理】制造行业中汽车厂房综合能效管理平台应用分析

安科瑞 李亚俊 平台概述 壹捌柒贰壹零玖捌柒伍柒AcrelEMS-EV汽车厂房能效管理平台集变电站综合自动化、电力监控、电气安全、电能质量分析及治理、能耗管理、能效分析、照明控制、充电桩运营管理、设备运维于一体&#xff0c;为建立可靠、安全的工厂能源管理体系提供数据支持…

【Flink】处理迟到元素(续)、自定义水位线和多流的合并与合流

文章目录一 处理迟到元素1 处理策略&#xff08;3&#xff09;使用迟到元素更新窗口计算结果a 代码编写b 测试二 自定义水位线1 产生水位线的接口2 自定义水位线的产生逻辑三 多流的合流与分流1 union算子2 水位线传递规则&#xff08;1&#xff09; 分流a 代码编写b 测试&…

virtio-net 实现机制【二】(图文并茂)

4. virio-net前端驱动分析 4.1 重要数据结构 4.1.1 send_queue结构 send_queue结构是对virtqueue的封装&#xff0c;是virtio-net的发送队列&#xff0c;即数据流向从前端驱动&#xff08;Guest&#xff09;到后端驱动&#xff08;Host&#xff09; 4.1.2 receive_queue结构…

【PlasticSCM Could Edition】新版本云托管浅试2

【PlasticSCM Could Edition】新版本云托管浅试2首先修复更改托管提一嘴首先 建议还是使用 PlasticHub&#xff0c;不要去用 PlasticSCM Cloud 原因&#xff1a; 由于比较新&#xff0c;伴随着的就是 —— 太多 bigs 了&#xff01;而且不知道怎么去改。 当时我创建了一个…

数据结构复习

期末的一套模拟题&#xff0c;仅供参考&#xff0c;切莫作为期末考试依据&#xff01;&#xff01;&#xff01; 选择题 数组A[1..5,1..6]每个元素占5个单元&#xff0c;将其按行优先次序存储在起始地址为1000的连续的内存单元中&#xff0c;则元素A[5,5]的地址为&#xff1a;…

轻量应用服务器部署vue项目

首先我已经拥有一个轻量云服务器了.windows2012的版本&#xff1a; 1.搭建 FTP 服务 为了将我们打包好的vue项目传到服务器&#xff0c;我们要先在服务器搭建FTP服务。 具体步骤可以参考官方文档&#xff0c;官方文档的教程十分清楚详细&#xff0c;按照步骤来就不会出错&am…

传奇服务端服务端运行7个窗口的各窗口功能讲解

大家都知道打开传奇版本里的游戏引擎后&#xff0c;就会弹出7各窗口&#xff0c;下面给大家讲解下各窗口的功能定义 GameCenter是游戏服务器启动程序&#xff0c;负责将DBServer.exe处转来的客户 端转发到相应的M2Server.exe。 DBServer.exe是用户数据库服务器&#xff0c;负责…

Allure与Jenkins持续集成

目标&#xff1a;每次提交代码到代码托管平台&#xff08;gitee&#xff09;&#xff0c;自动触发jenkins项目构建&#xff0c;生成allure测试报告&#xff0c;并发送邮件通知。 1、部署jenkins Jenkins — 快速入门 2、配置Gitee &#xff08;1&#xff09;Plugin Manager&…

01_openstack概述

一、openstack起源 Openstack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的项目Openstack是一套IaaS解决方案Openstack是一个开源的云计算管理平台以Apache许可证为授权二、Openstack七大组件 1、Horizaon组件 Horizon为Openstack服务的Web控制面板&#xff…

leecode#用Read4读取n个字符#相交链表

题目描述&#xff1a; 给你一个文件&#xff0c;并且该文件只能通过给定的 read4 方法来读取&#xff0c;请实现一个方法使其能够读取 n 个字符。 分析&#xff1a; read4 方法&#xff1a;API read4 可以从文件中读取 4 个连续的字符&#xff0c;并且将它们写入缓存数组 buf…

为什么电脑运行越来越慢?解决方法又是什么呢?

文章目录为什么电脑运行越来越慢&#xff1f;解决方法又是什么呢&#xff1f;一&#xff0c;电脑运行慢的原因二&#xff0c;提高电脑运行速度的方法1&#xff0c;重启电脑2&#xff0c;还原&#xff08;重置&#xff09;操作系统3&#xff0c;关闭不使用的应用程序4&#xff0…

CrossOver2023Win电脑软件操作在Mac、Linux系统运行教程

在Mac系统中一直存在一个比较令用户们头疼的问题&#xff0c;那就是安装不了想要的Windows软件。如果使用的第一台电脑就是MacBook那接触到的Windows软件想必并不是很多。但我们中的大多数人都是从小先学习了Windows的操作系统&#xff0c;再过渡到Mac系统上的。 那有小伙伴会…

面试:插件化相关---service

插件service启动分析 同样的&#xff0c;先来看看service的常规启动流程 调用contextimpl.startService/bindService/stopService -> AMS&#xff0c;AMS对应创建ServiceRecord和token后&#xff0c;通知ActivityThreadActivityThread收到startService后&#xff0c;会创建…

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析(选择题)2022年9月

2022年9月scratch一级真题解析 选择题(共25题,每题2分,共50分) 1、点击绿旗,下列哪个选项可以实现播放马叫声并在声音全部播放完后,马向右移动 A、 B、 C、 D、

[附源码]计算机毕业设计JAVA小说网站的设计与实现1

[附源码]计算机毕业设计JAVA小说网站的设计与实现1 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM m…

基于RV1126 Video分析-----链接 isp 与mipi csi 的media模块

从前文&#xff1a;<<图像处理模块所代表的V4L2设备注册>> 中了解到。rkcif_mipi设备注册的过程就是以设备通知器为线索&#xff0c;从顶向下&#xff0c;依次找到下一级设备&#xff0c;添加到V4L2设备种&#xff0c;循环处理。将全部的子设备整理到 V4L2设备中&a…

《InnoDB引擎五》Checkpoint技术

Checkpoint技术 缓冲池的设计目的是为了协调CPU速度与磁盘速度的鸿沟。因此页的操作首先都是在缓冲池中完成的。如果一条DML语句&#xff0c;比如Update或Delete改变了页中的记录&#xff0c;那么此时页是脏的&#xff0c;即缓冲池中的页要比磁盘的新&#xff0c;那么数据库就需…

网络编程简单学习

目录 一、 概述 1. 什么是计算机网络&#xff1f; 2. 网络编程的目的 3. 需要达到什么样的效果&#xff1f; 二、 网络通信的两个要素 1. 通信双方地址 2. 规则&#xff1a;网络通信协议 三、IP地址 1. IP地址概述 2. IP地址分类 3. 域名 四、端口 五、通信协议 …

Python破解WIFI密码完整源代码,实测可成功破解

目录 # 修正记录&#xff1a;2022-12-01 1&#xff0c;先安装Python环境(这个不用多说了吧) 2&#xff0c;安装PyWifi 3,自己手工整理高频弱口令&#xff0c;不建议程序生成的字典&#xff0c;生成的字典成功率实在太低。 4&#xff0c;自己生成字典的算法&#xff1a; 5…