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…

树状数组+离散化求逆序对超详细讲解!

树状数组离散化求逆序对 用一个数组 w [ ] w[] w[]来记录遍历到当前数时&#xff0c;每个数出现的次数 由于只关心每个数前边有多少个数比他大&#xff0c;遍历到 i i i时&#xff0c;求大于 a [ i ] a[i] a[i]的数有多少个&#xff0c;就是对 [ a [ i ] , n ] [a[i], n] [a[i…

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;一直在推动行业不断向前发展。 从基础算…

详谈数据结构数组名的含义

谈及背景 int a[3]; sizeof(arr) 12B &#xff0c;这个让我很不理解&#xff0c;后来通过一系列调查研究出了sizeof 一些性质: sizeof()是单目运算符&#xff0c;和‘’一样&#xff0c;不是库函数。sizeof()算结构体的大小 有对应的规则 算结构体大小与结构体中成员排列的顺序…

c++ primer中文版第五版作业第十八章

仓库地址 文章目录 18.118.218.318.418.518.618.718.818.918.1018.1118.1218.1318.1418.1518.16位置一using声明 位置二using声明 位置一using指示 位置二using指示 18.1718.1818.1918.2018.2118.2218.2318.2418.2518.2618.2618.2818.2918.30 18.1 此时r是一个range_error类型…

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

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

WebGL之使用着色器将颜色应用于 WebGL

在之前的展示中我们已经创建好了一个正方形&#xff0c;接下来我们要做的就是给它添加一抹色彩。添加颜色可以通过修改着色器来实现。 给顶点着色 在 WebGL 中&#xff0c;物体是由一系列顶点组成的&#xff0c;每一个顶点都有位置和颜色信息。在默认情况下&#xff0c;所有像…

异常-Exception

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

Basis运维日常检查清单- Checklist

检查SYSTEM 是否正常GUI登入登入到系统检查所有应用服务器是否活动正常SM51检查所有SAP Instance服务器运行是否正常.检查工作进程进行SM50检查是否有运行时间很长Local ProcessSM66检查是否有运行时间很长Global Process检查陈旧锁定条目SM12在User ID栏输入*. 检查前期的锁列…

网络编程聊天室

客户端 #include <myhead.h> //创建结构体存储用户信息 struct User {char tape;char username[32];char msg[1024]; };int main(int argc, const char *argv[]) {//创建套接字与服务器进行通信int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){perror("socket err…

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

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

django默认后台管理显示内容深化设置

1、设置models字段展示为只读模式 如某个字段在展示时不允许修改&#xff0c;可在admin.py的注册类下重写函数get_readonly_fields&#xff0c;例&#xff1a; def get_readonly_fields(self, request, objNone): return (dwdm,dwmc,"zjs","yyj"…

ARC-Challenge数据集分享

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

#微信小程序(按键控制)

1.IDE&#xff1a;微信开发者工具 2.实验&#xff1a;微信小程序设计两个按钮&#xff0c;对onenet平台数据流&#xff08;旧版&#xff09;来进行http post上传&#xff0c;下位机再http get得到控制信息 3.记录 &#xff08;1&#xff09;bind-tap&#xff08;绑定函数&…

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

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

Linux shell 网络掩码地址转CIDR

例子&#xff1a; ./1.sh 255.255.255.0 ./1.sh 255.255.255.128 ./1.sh 255.255.0.0 源实现&#xff1a; #!/bin/bashnetmask_to_cidr() {local IFSlocal -a octetslocal i0local cidr0IFS. read -r -a octets <<< "$1"for octet in "${octets[]}…

Sora关于视频分镜的提示词技巧

视频分镜是视频制作中至关重要的一环&#xff0c;它决定了视频内容的结构、节奏和视觉效果。在Sora文生视频模型中&#xff0c;通过巧妙地运用提示词&#xff0c;你可以更加高效地进行视频分镜设计&#xff0c;提升视频的质量和观众体验。以下是10个关于视频分镜的提示词技巧&a…

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…