C++第二十弹---深入理解STL中vector的使用

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】

目录

1、vector的介绍

2、vector的使用

2.1、构造函数和赋值重载

2.1.1、构造函数的介绍

2.1.2、代码演示

2.2、容量操作

2.3、遍历

2.4、增删改

总结


1、vector的介绍

vector文档介绍icon-default.png?t=N7T8https://cplusplus.com/reference/vector/vector/

 1. vector是表示可变大小数组的序列容器。

 

2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。


2、vector的使用


vector学习时一定要学会查看文档:vector的文档介绍,vector在实际中非常的重要,在实际中我们熟悉常见的接口就可以,下面列出了哪些接口是要重点掌握的。


2.1、构造函数和赋值重载

2.1.1、构造函数的介绍

1. Default constructor (default (1)):

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

这是 std::vector 的空容器构造函数(默认构造函数)。它构造一个没有元素的空容器。可选参数 alloc 是一个分配器对象,用于指定内存分配模型(后面会学到)explicit 关键字表示构造函数防止隐式转换或复制初始化。大多数时候,你可以简单地省略分配器,因为它有一个默认值。

2. Fill constructor (fill (2)):

explicit vector (size_type n, const value_type& val = value_type(),
                 const allocator_type& alloc = allocator_type());

这是 std::vector 的填充构造函数。这个构造函数构造了一个含有 n 个元素的容器,每个元素都是 val 的副本。val 是可选的;如果不提供,则使用该类型的默认构造函数创建元素。同样,alloc 是可以省略的可选分配器。explicit 关键字仅在只提供了 n 参数的情况下有作用,当同时提供 n 和 val 时,可以使用复制初始化。

3. Range constructor (range (3)):

template <class InputIterator>
vector (InputIterator first, InputIterator last,
        const allocator_type& alloc = allocator_type());

这是 std::vector 的范围构造函数。这个构造函数使用两个迭代器 first 和 last,这两个迭代器指定了一个序列的范围,来构造一个容器。这个范围包括从 first 到 last 之间的所有元素但不包括 last 指向的元素。这个构造函数可以用于复制任何其他容器(如 list、deque、甚至是另一个 vector)中的元素。分配器 alloc 是可选的。

4. Copy constructor (copy (4)):

vector (const vector& x);

这是 std::vector 的赋值(拷贝)构造函数构造一个容器,其中包含 x 中每个元素的副本,顺序相同。

5. copy

 vector& operator= (const vector& x);

这是 std::vector 的赋值操作符重载将新内容分配给容器,替换其当前内容,并相应地修改其大小。 

2.1.2、代码演示

#include<iostream>
#include<vector>
using namespace std;

int main()
{
    //1.默认构造函数
    vector<int> v;
    //2.填充构造函数
    vector<int> v1(5, 1);//构造n个元素,初始化为1
    //3.范围构造函数
    vector<int> v2(v1.begin(), v1.end());//构造v1的起始位置到结束为止,左闭右开
    //4.拷贝构造函数
    vector<int> v3(v2);//将v2数组的元素拷贝给v3
    //5.赋值操作符重载
    vector<int> v4 = v3;//将v3数组的元素拷贝给v3

    //使用范围for打印
    for (auto x : v)
    {
        cout << x << " ";
    }
    cout << endl;
    for (auto x : v1)
    {
        cout << x << " ";
    }
    cout << endl;
    for (auto x : v2)
    {
        cout << x << " ";
    }
    cout << endl;
    for (auto x : v3)
    {
        cout << x << " ";
    }
    cout << endl;
    for (auto x : v4)
    {
        cout << x << " ";
    }
    cout << endl;
    return 0;
}

2.2、容量操作

size_t size();

获取数组的大小。

size_t capacity()

获取数组的容量。

int main()
{
    vector<int> v(10, 1);
    cout << "size() = " << v.size() << endl;//大小
    cout << "capacity() = " << v.capacity() << endl;//容量
    return 0;
}

 看看扩容机制:

int main()
{
    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);//尾插一个元素i
        if (sz != v.capacity())//初始容量与现在容量不相等则更新
        {
            sz = v.capacity();
            cout << "capacity changed: " << sz << '\n';//修改后的容量
        }
    }
    return 0;
}

vs结果如下:

 

vs下使用的STL基本是按照1.5倍方式扩容。 

 g++结果如下:

linux下使用的STL基本是按照2倍方式扩容。 

reserve(size_t n)

更改容量。

如果 n 大于当前容量,则该函数会导致容器重新分配其存储,将其容量增加到 n(或更大)。

在所有其他情况下,函数调用不会导致重新分配(无需扩容),并且向量容量不受影响。

用来预先开辟容量大小,来减少扩容次数:

int main()
{
    vector<int> v;
    size_t sz = v.capacity();
    v.reserve(100); // 将容量扩大至100,开辟100个数的空间
    cout << "making reserve 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';
        }
    }
    return 0;
}

 测试结果:

resize()

调整容器的大小,使其包含 n 个元素。

  1. 如果 n 小于当前容器大小,则内容将减少到其前 n 个元素,删除超出(并销毁它们)的元素。
  2. 如果 n 大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容,以达到 n 的大小。如果指定了 val,则新元素将初始化为 val 的副本否则,它们将进行值初始化。
  3. 如果 n 也大于当前容器容量,则会自动重新分配分配的存储空间(即需要扩容)。
int main()
{
    vector<int> v;
    v.resize(10, 1);//调整大小为10,并初始化为1
    for (auto x : v)
    {
        cout << x << " ";
    }
    cout << endl;
    return 0;
}

测试结果:

 

总结:

reserve只负责开辟空间,如果确定知道需要用多少空间reserve可以缓解vector增容的代价缺陷问题(细节)

resize在开空间的同时还会进行初始化,影响size。

resize不会进行缩容,如果想要缩容,我们可以调用shrink_to_fit()函数

2.3、遍历

operator[ ](size_t n)

获取下标为n的元素。

int main()
{
    vector <int> v1(10, 1);
    for (size_t i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";//重载[]遍历数组
    }
    cout << endl;
    return 0;
}

测试结果:

 

迭代器iterator

begin();指向第一个元素。

end();指向最后一个元素的下一个。

rbegin();指向最后一个元素的下一个。

rend();指向第一个元素。

int main()
{
    vector<int> v(10, 1);
    vector<int>::iterator it = v.begin();//迭代器返回类型
    while (it != v.end())//使用迭代器遍历数组
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    return 0;
}

测试结果: 

2.4、增删改

push_back(); 

在末尾添加元素。
数组的末尾添加一个新元素(在当前最后一个元素之后)。val 的内容将被复制(或移动)到新元素。

这实际上将容器大小增加了一个,当且仅当新的向量大小超过当前向量容量时,才会自动重新分配分配的存储空间。

pop_back();

删除最后一个元素。
删除数组中的最后一个元素,从而有效地将容器大小减小一个

int main()
{
    vector<int> v;
    v.push_back(1);//尾插1
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    for (auto x : v)//打印数组
    {
        cout << x << " ";
    }
    cout << endl;
    v.pop_back();//尾删
    v.pop_back();
    for (auto x : v)
    {
        cout << x << " ";
    }
    return 0;
}

测试结果: 

 

insert();

插入元素。
通过在指定位置的元素之前插入新元素来扩展向量,从而有效地通过插入的元素数量增加容器大小。C++98重载了三种插入方式。

1. Single element (1):

iterator insert (iterator position, const value_type& val);

这个方法在数组中 position 指定的位置前插入一个 val 副本,并返回指向新插入元素的迭代器。如果 position 是向量的 end() 迭代器,则新元素被添加到向量的末尾(尾插)


2. Fill (2):

void insert (iterator position, size_type n, const value_type& val);

这个方法在 position 指定的位置前插入 n 个 val 副本。它不返回任何值。


3. Range (3):

template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);

这个方法将位于 [first, last) 区间内的元素插入到 position 指定的位置前。这个范围包括 first,但不包括 last,即它是一个半开区间。这个方法也不返回任何值。

举例:

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	for (auto x : v)
	{
		cout << x << " ";
	}
	cout << endl;
	auto it = v.begin();
	it = v.insert(it, 10);//在1之前插入10
	for (auto x : v)
	{
		cout << x << " ";
	}
	cout << endl;
	it = v.insert(it, 2, 20);//在10之前插入两个20
	for (auto x : v)
	{
		cout << x << " ";
	}
	cout << endl;
	vector<int> v1;
	//在v1第一个位置插入v数组
	v1.insert(v1.begin(), v.begin(), v.end());
    return 0;
}

测试结果:

 

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

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

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

相关文章

类和对象(上)【有关类的全面学习】【this指针的学习】

类和对象&#xff08;上&#xff09; 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C语言注重过程&#xff1a; C是基于面向对象的&#xff0c;关注的是对象&#xff0…

如何获取某个城市或区域的人口分布数据?

人口分布数据在多个领域都扮演着至关重要的角色。这些数据不仅反映了一个国家或地区的人口分布状况&#xff0c;而且为政策制定者、企业决策者和研究者提供了宝贵的信息。那么&#xff0c;我们如何获取这些重要的人口分布数据呢&#xff1f; 政府统计部门是最主要的来源。各国政…

绝缘鞋计量校准周期多长时间合适?校验检测方法是什么?

绝缘鞋的计量校准&#xff0c;通常是应用在电学相关领域&#xff0c;因此也是属于计量校准机构中的电学室管辖的范围&#xff0c;而绝缘鞋为了安全防护&#xff0c;也是采用了绝缘材料&#xff0c;其标准要求耐电压至少在15KV以下&#xff0c;可应用于工频&#xff08;50到60F&…

git 检查用户是否是gitlab用户

背景: 公司代码要从老的git库迁到新的git库&#xff0c;老git库上部分提交用户在新git库上没有&#xff0c;解决方法: 让gitlab不再检查提交用户是否是gitlab用户。具体操作: 去掉下面的勾选&#xff0c;保存配置即可。

天气的雪碧图标(晴天,雨天,雪天,阴天,雾天,多云等)(2024-05-27)

天气的预览图标&#xff0c;可以自行下载&#xff0c;或者在资源中下载高清的

Matlab进阶绘图第57期—带填充纹理的横向柱状图

带填充纹理的横向柱状图是通过在原始横向柱状图的基础上添加不同的纹理得到的&#xff0c;可以很好地解决由于颜色区分不足而导致的对象识别困难问题。 由于Matlab中未提供纹理填充选项&#xff0c;因此需要大家自行设法解决。 本文使用Kesh Ikuma制作的hatchfill2工具&#…

buu[HCTF 2018]WarmUp(代码审计)

buu[HCTF 2018]WarmUp&#xff08;代码审计&#xff09; 题目 访问source.php <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php…

屎山代码SSM转换Springboot

SSM项目转Springboot项目 最近很多人可能是在网上买的那种屎山代码&#xff0c;数据库都是拼音的那种 比如项目如下所示&#xff1a; 这种屎山代码我改过太多了&#xff0c;很多人可能无从下手&#xff0c;因为代码结构太混乱了&#xff0c;但是我改过太多这种代码&#xff0…

【SpeedAI科研小助手】2分钟解决知网维普AIGC检测

2分钟搞定AIGC率&#xff1f;还能降到0%&#xff1f; 使用方法&#xff1a; 打开SpeedAI科研小助手&#xff0c;将功能模式换成降AIGC率&#xff0c;后面可以一段一段自己改&#xff0c;也可以直接上传论文文件&#xff0c;SpeedAI直接帮你全文修改&#xff08;主打一个用户友…

【云原生】kubernetes中的认证、权限设置---RBAC授权原理分析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

笔记本电脑的ip地址在哪里找

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;扮演着至关重要的角色。对于笔记本电脑用户而言&#xff0c;了解如何查找自己的IP地址不仅有助于网络故障排查&#xff0c;还能在网络安全和远程办公等场景中发挥关键作用。虎观代理小二将详细介绍笔记本电脑…

关于linux磁盘告警问题

案例&#xff1a;我们在执行df命令时&#xff0c;查看到磁盘利用率很高&#xff0c;但是到相对应的目录执行du -sh *来找大文件时进行删除时&#xff0c;发现各个目录相加并不大&#xff0c;如下图&#xff1a; 使用df命令查看到根(/)目录使用到33G&#xff0c;而du命令显示只使…

【一竞技DOTA2】北美SR战队官宣SabeRLighT-离队

1、近日北美SR战队官宣了旗下三号位选手SabeRLighT-正式离队&#xff0c;公告内容如下&#xff1a; “今日我们正式宣布&#xff0c;Jonas &#xff08;Saberlight&#xff09;Volek将离开队伍。这个决定由Jonas本人和其他团队成员共同做出。 在过去的几个月里&#xff0c;我们…

mysql中InnoDB的表空间--独立表空间

大家好&#xff0c;上篇文章我们在讲mysql数据目录的时候提到了表空间这个名词&#xff0c;它是一个抽象的概念&#xff0c;对于系统表空间来说&#xff0c;对应着文件系统中一个或多个实际文件&#xff1b;对于每个独立表空间来说&#xff0c;对应着文件系统中一个名为表名.ib…

中医理疗元宇宙 科技赋能中医药产业走向国际市场

基于380亿参数量&#xff0c;对中医药海量文本进行数据训练&#xff0c;实现方剂优化、机制阐释和新适应症的精准发现……日前在天津召开的数智赋能大健康产业新质生产力暨第四届中医药国际发展大会上&#xff0c;由天士力医药集团与华为云共同开发的“数智本草”中医药大模型正…

QT C++ QTableWidget+combobox 槽函数 演示

本文演示了 QTableWidget的初始化以及单元格值改变时响应槽函数&#xff0c;打印单元格。 并且&#xff0c;最后列不一样,是组合框(combobox) &#xff0c;此列的槽函数用lambda函数。 在QT6.2.4 MSVC2019 调试通过。 1.界面效果 2.头文件 #ifndef MAINWINDOW_H #define MA…

关于Nginx热部署的细节分析

文章目录 前言一、环境准备二、热部署步骤总结 前言 Nginx由于其高并发、高性能、可扩展性好、高可靠性、热部署、BSD许可证等优势被广泛使用&#xff0c;本人主要针对热部署的部分展开说明热部署的具体步骤以及步骤背后发生的具体事情。 本次热部署采用的Nginx版本号为&…

【Web】2024京麒CTF ezjvav题解

目录 step 0 step 1 step 2 EXP1 EXP2 step 0 进来是一个登录框 admin/admin成功登录 访问./source jwt伪造 带着伪造的jwt访问./source&#xff0c;拿到题目源码jar包 step 1 pom依赖有spring、fj、rome 反序列化入口在./Jsrc路由 有两层waf&#xff0c;一个是明…

科技与心理学的协同舞蹈

在探讨盲人如何利用如“蝙蝠避障”这样的辅助软件融入日常生活的同时&#xff0c;我们不得不深入触及盲人教育心理学的核心&#xff0c;这一领域致力于理解盲人在学习与成长过程中独特的心理需求与挑战&#xff0c;以及如何通过教育策略激发他们的潜能&#xff0c;促进全面发展…