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.hqwc.cn/news/522943.html

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

相关文章

C++ 智能指针深度剖析

文章目录 1. 前言2. 为什么需要智能指针&#xff1f;3. 内存泄漏3.1 内存泄漏的概念及危害3.2 内存泄漏的分类3.3 如何检测内存泄漏3.4 如何避免内存泄漏 4. 智能指针的使用及原理4.1 RAII思想4.2 智能指针的原理4.3 C智能指针发展历史4.4 std::auto_ptr4.5 std::unique_ptr4.6…

746. 使用最小花费爬楼梯 (Swift版本)

题目 给你一个整数数组 cost&#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到楼梯顶部的最低花费。 限制条件 2…

一文扫荡,12个可视化图表js库,收藏备用。

hello&#xff0c;我是贝格前端工场&#xff0c;可视化图表在web前端开发中经常碰到&#xff0c;是不是很疑惑这些炫酷的图表是怎么实现的&#xff0c;其实是通过js库开发的&#xff0c;本文带来12个javascript库的介绍&#xff0c;欢迎关注我&#xff0c;阅读精彩内容。 一、什…

园区内部无线语音通信的解决方案

在一些园区、办公环境和厂矿场所&#xff0c;内部无线语音通信功能的需求日益凸显&#xff0c;尤其对于人员流动和移动办公的场景。这种需求着重强调了无线通信的便捷性和内部部署环境的适应性。 传统的内部通信系统中&#xff0c;有线通信能力占据主导地位&#xff0c;如集团…

嵌入式学习-FreeRTOS-Day3

嵌入式学习-FreeRTOS-Day3 一、思维导图 二、 1.FreeRTOS任务的调度算法及实现 默认是抢占式调度时间片轮询 1.抢占式调度&#xff1a;任务优先级高的可以打断任务优先级低的执行&#xff08;适用于不同优先级&#xff09; 2.时间片轮转&#xff1a;每一个任务拥有相同的时…

一张草图直接生成视频游戏,谷歌推出生成交互大模型

谷歌DeepMind的研究人员推出了&#xff0c;首个无需数据标记、无监督训练的生成交互模型——Generative Interactive Environments&#xff0c;简称“Genie”。 Genie有110亿参数&#xff0c;可以根据图像、真实照片甚至草图&#xff0c;就能生成各种可控制动作的视频游戏。Ge…

uniapp实现---类似购物车全选

目录 一、实现思路 二、实现步骤 ①view部分展示 ②JavaScript 内容 ③css中样式展示 三、效果展示 四、小结 注意事项 一、实现思路 点击商家复选框&#xff0c;可选中当前商家下的所有商品。点击全选&#xff0c;选中全部商家的商品 添加单个多选框&#xff0c;在将多选…

活动会议如何做好线上宣传?媒体直播怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 活动会议的线上宣传和媒体直播是提高活动曝光度和参与度的重要手段。以下是一些建议&#xff0c;以帮助您做好线上宣传和媒体直播&#xff1a; 一、线上宣传策略 制定宣传计划&#xff…

FreeRTOS学习笔记-基于stm32(3)中断管理

一、什么是中断 通俗点讲就是让CPU停止当前在做的事&#xff0c;转而去做更紧急的事。 二、中断优先级分组 这个紧急的事也有一个等级之分&#xff0c;优先级越高越先执行。stm32使用中断优先配置寄存器的高4位&#xff0c;共16级的中断优先等级。 stm32的中断优先等级可以分为…

VTune+Sampling Drivers环境搭建(本地和远程)

文章目录 一、实验环境二、Vtune安装2.1 下载2.2 安装2.3 测试2.4 检查2.5 部分功能开启2.5.1 ptrace2.5.2 Sampling Drivers 2.6 Memory Access功能 三、安装Sampling Drivers3.1 Sampling Drivers下载3.2 Sampling Drivers编译3.3 Sampling Drivers安装3.4 Sampling Drivers开…

03_JDBC

文章目录 数据库的访问流程JDBCJDBC实现流程使用JDBC进行增删改查增删改查 重要的APIDriverManagerConnectionStatementResultSet JDBC实现流程的优化数据库注入问题批处理for循环逐条插入statement批处理preparedStatement批处理 数据库的事务事务的步骤事务的API事务的特性事…

计算机组成原理之机器:存储器之高速缓冲存储器

计算机组成原理之机器&#xff1a;存储器之高速缓冲存储器 笔记来源&#xff1a;哈尔滨工业大学计算机组成原理&#xff08;哈工大刘宏伟&#xff09; Chapter3&#xff1a;存储器之高速缓冲存储器 3.1 概述 3.1.1 为什么用cache&#xff1f; 角度一&#xff1a;I/O设备向…