C++vector的使用方法

文章目录

  • 一、vector的介绍
    • 1. 文档链接
    • 2. 简要介绍
  • 二、vector的使用
    • 1.vector的定义
      • (1)构造函数
      • (2)拷贝构造函数
      • (2)赋值重载
    • 2. vector 增删查改
      • (1)operator []
      • (2)push_back和pop_back
      • (3)insert和erase
      • (4)find查找
    • 3. vector 空间增长问题
      • (1)size和empty及capacity
      • (2)resize和reserve
      • (3 reserve
      • (4 resize
    • 4. vector iterator 的使用
      • (1)begin和end
      • (2)rbegin和rend
      • (3)范围for


一、vector的介绍

1. 文档链接

参考文档
在这里插入图片描述

2. 简要介绍

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

二、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& operator= (const vector& x);赋值重载

(1)构造函数

  • vector的构造函数主要有三种
    • 无参构造
    • 放入n个相同的数据
    • 使用迭代器区间进行构造

其中的allocator是空间配置器,只是用来分配空间的,加快空间申请和释放的速度。
在这里插入图片描述
vector是一个模板类,在实例化的时候要指明其内置类型。

template < class T, class Alloc = allocator<T> > class vector;
void test1()
{vector<int> v1;//无参构造vector<int> v2(3, 2);//构造一个有3个2的vectorstring s1("abcd");vector<int> v3(s1.begin(), s1.end());//迭代器构造}

在这里插入图片描述

在这里插入图片描述
在迭代器构造的示例中我们可以看到v3的size是4,但是里面存的却不是字符abcd,那是因为我们实例化的时候类型写的是int,他这里发生了隐式类型转换。
如果想要看到正确的字符的话改成下面这样就好了

vector<char> v3;

vector<char>和string的区别:vector存的是一个一个的字符,结尾是没有'\0'的,而是string是字符串所以结尾会有'\0'

vector中不仅可以存自定义类型,它还可以放自定义类型,你创建的结构体什么的都可以放。因为【vector】是一个模版类,其会根据所传入的类型去做一个自动类型的推导,例如在vector中放入string对象,我们就可以直接这样写

vector<string> s1;

(2)拷贝构造函数

在这里插入图片描述
我们可以简单来看一下
在这里插入图片描述

void test2()
{vector<int> v1(3, 2);vector<int> v2(v1);//拷贝构造vector<int> v3 = v1;//这也是拷贝构造,不是赋值重载
}

在这里插入图片描述

(2)赋值重载

在这里插入图片描述
在这里插入图片描述

void test3()
{vector<int> v1(3, 2);vector<int> v2;v2 = v1;//赋值重载}

在这里插入图片描述

2. vector 增删查改

vector增删查改接口说明
push_back(重点)尾插
pop_back (重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[] (重点)像数组一样访问

(1)operator []

在vector中对[]进行了运算符重载,使得我们可以像通过下标访问数组元素一样来访问vector,同时支持修改

  • 下面是官方文档中的形式,虽然看起来很复杂,但是读者完全不用理会,会用就可以了
reference operator[] (size_type n);const_reference operator[] (size_type n) const;

在这里插入图片描述

void test4()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());for (int i = 0; i < s1.size(); i++){cout << v1[i] << " ";}//支持访问cout << endl;v1[0] = 'x';v1[1] = 'y';//支持修改for (int i = 0; i < s1.size(); i++){cout << v1[i] << " ";}
}

在这里插入图片描述

(2)push_back和pop_back

在数组尾部插入一个元素和删除最后一个元素。
在这里插入图片描述
在这里插入图片描述

void test4()
{string s1("hello,");vector<char> v1(s1.begin(), s1.end());for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.push_back('L');v1.push_back('i');v1.push_back('n');v1.push_back('u');v1.push_back('x');for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}
}

在这里插入图片描述
如果我们这里采取string类作为【vector】的内置类型,然后通过三种形式往里面插入数据:

  • 第一种是构造出具体的对象
  • 第二种采取的是匿名对象
  • 第三种采取的则是单参数的构造函数所引发的 隐式类型转换
void test5()
{vector<string> v;string name1("张三");v.push_back(name1);v.push_back(string("李四"));v.push_back("王五");		// 单参数的构造函数支持隐式类型转换
}

在这里插入图片描述

(3)insert和erase

在这里插入图片描述
在这里插入图片描述

insert有很多,这里仅仅展示部分常用的两参数的,第一个参数是要插入位置的迭代器,第二个是要插入的元素。

void test7()
{vector<string> v;v.push_back("张三");v.push_back("王五");v.insert(v.begin() + 1, "李四");//在begin的下一个位置插入一个元素for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.erase(v.begin());//删除begin位置的元素for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}}

在这里插入图片描述
如果想要删除指定元素,我们可以find和erase搭配使用

(4)find查找

在这里插入图片描述
find是在范围内查找,观察函数的参数我们可以知道如果要使用这个函数的话就需要先传入一个迭代器区间,然后传入一个值,在指定的区间内查找这个值。如果找到则返回指向改元素位置的迭代器,如果找不到那就返回最后的迭代器也就是end()

void test6()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());std::vector<char>::iterator it = find(v1.begin(), v1.end(), 'w');if (it != v1.end()){cout << *it << endl;}}

在这里插入图片描述
我们可以搭配erase加循环使用,删除vector中所有的 ‘l’ 字符

void test6()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());std::vector<char>::iterator it = find(v1.begin(), v1.end(), 'l');while (it != v1.end()){it = v1.erase(it);it = find(it, v1.end(), 'l');}for (auto e : v1){cout << e << " ";}cout << endl;}

在这里插入图片描述

3. vector 空间增长问题

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize(重点)改变vector的size
reserve (重点)改变vector的capacity

(1)size和empty及capacity

size就是获取容器中有几个元素,capacity就是容器的容量
capacity和size是不一样的,你可以开10个空间但只放5个数据,此时size就是5,而capacity就是10.

void test10()
{vector<int> v(5, 10);cout << v.size();
}

可以看到我们插入了5个10,所以size是5,capacity也是5.
在这里插入图片描述

empty就是判断容器是否有元素,没有元素返回1,有元素返回0

void test11()
{vector<int> v;cout << v.empty() << endl;//没元素所以为真,输出1v.push_back(1);cout << v.empty();//插入一个元素后不为空,输出0
}

在这里插入图片描述

(2)resize和reserve

vector是可以自动扩容的,但频繁扩容是浪费时间的,所以我们可以提前开足够的空间,提高效率。

我们可以探索一下vector的扩容机制

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

可见在vs中,vector是按1.5倍的规则扩容的,我们去Linux平台下再去试试。
在这里插入图片描述
可以看到在Linux平台下是按照2倍的扩容逻辑走的。可见不同地方vector的实现方法略有区别。
在这里插入图片描述

(3 reserve

reserve是开好空间但不填充元素,所以size是不改变的,只有capacity会改变。因为size没改变,所以不能通过[]来访问没元素的位置。

void TestVectorExpandOP()
{vector<int> v;size_t sz = v.capacity();v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容cout << "making bar 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';}}
}

可以看到避免了频繁扩容
在这里插入图片描述

(4 resize

resize是开好指定的空间并填充默认值,capacity和size都会改变
可以看到size和capacity都是3,填充的默认值我们没有指定,所以默认填充的是0。
在这里插入图片描述
当然我们可以指定填充的内容,比如这里我们指定填充数字10
在这里插入图片描述
接下来我们说一下常见的错误
大家可以看看下面的代码有什么问题,是不是乍一看好像每什么问题,但是一运行直接寄了。

void test13()
{vector<int> v1;v1.reserve(10);for (size_t i = 0; i < 10; i++){v1[i] = i;}
}

在这里插入图片描述

  • 大家要关注前面的reserve(10),我们在上面说到对于【reserve】而言只是做的扩容而已,即只变化capacity,而不会变化size
  • 另一点,对于v1[i]我们上面在讲元素访问的时候有说到过,这是下标 + []的访问形式,在出现问题的时候会直接给出断言错误。因为这里我们在【reserve】的时候只是开出了指定的空间,但size还是为0,此时去访问的时候肯定就出错了

改正方法就是将reserve改成resize即可
可以看到成功运行
在这里插入图片描述

4. vector iterator 的使用

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

在这里插入图片描述

(1)begin和end

  • 和【string】中一样,每个迭代器也是具有两种形式,第一个呢是具有读写的,第二个则是只读的const迭代器
  • begin获取一个字符的迭代器
  • end获取最后一个字符下一个位置的迭代器
    在这里插入图片描述
    在这里插入图片描述
    迭代器的理解,迭代器呢可以说是STL中很重要的一部分。简单来说迭代器就是用来遍历或访问容器中的数据的,我们暂时可以把迭代器想象成指针,通过指针的++或者–加解引用的方式,我们就可以遍历一个数组,或者访问数组中的元素。当然指针只是迭代器中的一种,迭代器要实现的目的就是通过++或者–能够遍历容器中所有的元素,我们数组是一段连续的空间,可以通过指针加一的方式遍历整个数组,但是如果是链表呢?这种情况下通过对每个指针++的操作就无法实现目的了,因此指针就不适合当迭代器了,我们就得封装新的迭代器。
void test8()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());vector<char>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";//通过解引用迭代器获取容器中的元素++it;//迭代器++,指向下一个位置}
}

在这里插入图片描述

(2)rbegin和rend

rbegin和rend是反向迭代器
在这里插入图片描述
在这里插入图片描述
反向迭代器呢顾名思义就是从反方向进行遍历

void test8()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());vector<char>::iterator it1 = v1.begin();while (it1 != v1.end()){cout << *it1 << " ";++it1;}cout << endl;auto it2 = v1.rbegin();while (it2 != v1.rend()){cout << *it2 << " ";++it2;}
}

在这里插入图片描述

(3)范围for

既然支持迭代器的话,那肯定支持范围for的,我们可以来试试。

void test9()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());for (auto e : v1){cout << e << " ";}
}

可以看到没有任何问题。
在这里插入图片描述

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

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

相关文章

[HackMyVM]靶场 Quick3

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (U…

HTML—常用标签

常用标签&#xff1a; 标题标签&#xff1a;<h1></h1>......<h6></h6>段落标签&#xff1a;<p></p>换行标签&#xff1a;<br/>列表&#xff1a;无序列表<ul><li></li></ul> 有序列表<ol>&…

她们正在影响AI进程

今天是3月8日&#xff0c;祝广大女性同胞节日快乐&#xff01; 当下&#xff0c;人工智能正是全球科技圈最受关注的领域&#xff0c;甚至没有之一。 在人工智能领域诞生兴起的几十年内&#xff0c;女性科学家作为重要力量&#xff0c;一直在推动行业不断向前发展。 从基础算…

并查集(蓝桥杯 C++ 题目 代码 注解)

目录 介绍&#xff1a; 模板&#xff1a; 题目一&#xff08;合根植物&#xff09;&#xff1a; 代码&#xff1a; 题目二&#xff08;蓝桥幼儿园&#xff09;&#xff1a; 代码&#xff1a; 题目三&#xff08;小猪存钱罐&#xff09;&#xff1a; 代码&#xff1a; …

异常-Exception

文章目录 异常-Exception常见的运行时异常NullPointerException&#xff08;空指针异常&#xff09;ArithmeticException&#xff08;数学运算异常&#xff09;ArrayIndexOutOfBoundsException&#xff08;数组下标越界异常&#xff09;ClassCastException&#xff08;类型转换…

鸿蒙实战开发Camera组件:【相机】

相机组件支持相机业务的开发&#xff0c;开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发&#xff0c;最常见的操作如&#xff1a;预览、拍照和录像等。 基本概念 拍照 此功能用于拍摄采集照片。 预览 此功能用于在开启相机后&#xff0c;在缓冲区内重复采集…

ARC-Challenge数据集分享

来源: AINLPer公众号&#xff08;每日干货分享&#xff01;&#xff01;&#xff09; 编辑: ShuYini 校稿: ShuYini 时间: 2024-2-28 该数据集由Allen Institute for Artificial Intelligence&#xff08;AI2&#xff09;发布&#xff0c;旨在推动高级问答的研究。该数据集包含…

3D数字孪生运行不起来?该检查你的电脑配置了

运行3D数字孪生项目通常需要一定的计算资源和图形处理能力。以下是一些常见的电脑配置要求&#xff0c;可以作为参考&#xff1a;1处理器&#xff08;CPU&#xff09;&#xff1a;推荐使用多核心处理器&#xff0c;如Intel Core i7或更高级别的处理器。较高的时钟频率和较大的缓…

kafka报文模拟工具的使用

日常项目中经常会碰到消费kafka某个topic的数据&#xff0c;如果知道报文格式&#xff0c;即可使用工具去模拟发送报文&#xff0c;以此测试代码中是否能正常消费到这个数据。 工具资源已上传&#xff0c;可直接访问连接下载&#xff1a;https://download.csdn.net/download/w…

CSS补充(下),弹性布局(上)

高级选择器 1.兄弟选择器 2.同时满足 div.bg{background-color: red;}p.bg{background-color: green;}spam.bg{background-color: blue;}注&#xff1a;选择器中间没有空格&#xff0c;有明确标识的选择器写在后面 3.各种伪类的应用 3.1作为第几个子元素 选择器:nth-child…

React-父传子

1.概念 说明&#xff1a;父组件传递数据子组件标签身上绑定属性&#xff1b;子组件接受数据props的参数。props是一个对象&#xff0c;包含父组件传递的所有数据。例如数字、字符串、布尔值、数组、对象、函数、JSX。不允许直接修改父组件传递的数据。 2.例子 // 父传子 // …

uniapp踩坑之项目:uni.previewImage简易版预览单图片

主要使用uni.previewImage //html <view class"box-card" v-for"(item,index) in DataList" :key"index"><view>图片&#xff1a;</view><image :src"item.Path" tap.stop"clickImg(item.Path)">&l…

有点NB的免费wordpress主题模板

一个不错的黄色模板&#xff0c;用WP免费主题模板搭建家政服务公司网站。 https://www.wpniu.com/themes/15.html

【性能】JDK和Jmeter的安装与配置

一、JDK环境配置 1. 下载JDK 官网下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html 选择对应系统的安装包&#xff0c;下载后安装&#xff0c;安装中记录JDK安装的地址&#xff0c;之后一直点击下一…

继深圳后,重庆与鸿蒙展开原生应用开发合作

截至2023年底&#xff0c;开源鸿蒙开源社区已有250多家生态伙伴加入&#xff0c;开源鸿蒙项目捐赠人达35家&#xff0c;通过开源鸿蒙兼容性测评的伙伴达173个&#xff0c;累计落地230余款商用设备&#xff0c;涵盖金融、教育、智能家居、交通、数字政府、工业、医疗等各领域。 …

【Python】科研代码学习:三 PreTrainedModel, PretrainedConfig, PreTrainedTokenizer

【Python】科研代码学习&#xff1a;三 PreTrainedModel, PretrainedConfig, PreTrainedTokenizer 前言Models : PreTrainedModelPreTrainedModel 中重要的方法 tensorflow & pytorch 简单对比Configuration : PretrainedConfigPretrainedConfig 中重要的方法 Tokenizer : …

Java基础面试题(day 01)

&#x1f4d1;前言 本文主要是【Java】——Java基础面试题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

C++ 篇 数组

数组是含有多个数据项的数据结构&#xff0c;并且这些数据项都具有相同的数据类型。这些数据项称为数组的元素&#xff0c;我们可以根据元素在数组中的位置来选取元素。 最简单的数组就是一维数组。数组元素在内存中是依次排列的&#xff0c;如下图所示&#xff1a; 声明一个…

C++之创建与使用dll

目录 1、创建dll test.h test.cpp Source.def 2、使用dll testdll.cpp DLL&#xff0c;全称“Dynamic Link Library”&#xff0c;中文名为“动态链接库”&#xff0c;是一种在Windows操作系统中常见的库文件格式。它包含了可以由多个程序同时使用的代码和数据。与静态链接…

人工智能|机器学习——k-近邻算法(KNN分类算法)

1.简介 k-最近邻算法&#xff0c;也称为 kNN 或 k-NN&#xff0c;是一种非参数、有监督的学习分类器&#xff0c;它使用邻近度对单个数据点的分组进行分类或预测。虽然它可以用于回归问题&#xff0c;但它通常用作分类算法&#xff0c;假设可以在彼此附近找到相似点。 对于分类…