C++中vector用法

2023-10-27

vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的.
     用法:

1.文件包含:

首先在程序开头处加上#include以包含所需要的类文件vector

还有一定要加上using namespace std;

2.变量声明:

2.1 例:声明一个int向量以替代一维的数组:vector a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除)。

2.2 例:用vector代替二维数组.其实只要声明一个一维数组向量即可,而一个数组的名字其实代表的是它的首地址,所以只要声明一个地址的向量即可,即:vector <int > a.同理想用向量代替三维数组也是一样,vector <int*>a;再往上面依此类推.

3.具体的用法以及函数调用:

3.1 如何得到向量中的元素?其用法和数组一样:

例如:

vector <int *> a

int b = 5;

a.push_back(b);//该函数下面有详解

cout<<a[0];       //输出结果为5

1.push_back   在数组的最后添加一个数据
2.pop_back    去掉数组的最后一个数据 
3.at                得到编号位置的数据
4.begin           得到数组头的指针
5.end             得到数组的最后一个单元+1的指针
6.front        得到数组头的引用
7.back            得到数组的最后一个单元的引用
8.max_size     得到vector最大可以是多大
9.capacity       当前vector分配的大小
10.size           当前使用数据的大小
11.resize         改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve      改变当前vecotr所分配空间的大小
13.erase         删除指针指向的数据项
14.clear          清空当前的vector
15.rbegin        将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend          将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty        判断vector是否为空
18.swap         与另一个vector交换数据

3.2  详细的函数实现功能:其中vector c.

c.clear()         移除容器中所有数据。

c.empty()         判断容器是否为空。

c.erase(pos)        删除pos位置的数据

c.erase(beg,end) 删除[beg,end)区间的数据

c.front()         传回第一个数据。

c.insert(pos,elem)  在pos位置插入一个elem拷贝

c.pop_back()     删除最后一个数据。

c.push_back(elem) 在尾部加入一个数据。

c.resize(num)     重新设置该容器的大小

c.size()         回容器中实际数据的个数。

c.begin()           返回指向容器第一个元素的迭代器

c.end()             返回指向容器最后一个元素的迭代器

4.内存管理与效率

1》使用reserve()函数提前设定容量大小,避免多次容量扩充操作导致效率低下。

关于STL容器,最令人称赞的特性之一就是是只要不超过它们的最大大小,它们就可以自动增长到足以容纳你放进去的数据。(要知道这个最大值,只要调用名叫max_size的成员函数。)对于vector和string,如果需要更多空间,就以类似realloc的思想来增长大小。vector容器支持随机访问,因此为了提高效率,它内部使用动态数组的方式实现的。在通过 reserve() 来申请特定大小的时候总是按指数边界来增大其内部缓冲区。当进行insert或push_back等增加元素的操作时,如果此时动态数组的内存不够用,就要动态的重新分配当前大小的1.5~2倍的新内存区,再把原数组的内容复制过去。所以,在一般情况下,其访问速度同一般数组,只有在重新分配发生时,其性能才会下降。正如上面的代码告诉你的那样。而进行pop_back操作时,capacity并不会因为vector容器里的元素减少而有所下降,还会维持操作之前的大小。对于vector容器来说,如果有大量的数据需要进行push_back,应当使用reserve()函数提前设定其容量大小,否则会出现许多次容量扩充操作,导致效率低下。

reserve成员函数允许你最小化必须进行的重新分配的次数,因而可以避免真分配的开销和迭代器/指针/引用失效。但在我解释reserve为什么可以那么做之前,让我简要介绍有时候令人困惑的四个相关成员函数。在标准容器中,只有vector和string提供了所有这些函数。

(1) size()告诉你容器中有多少元素。它没有告诉你容器为它容纳的元素分配了多少内存。
(2) capacity()告诉你容器在它已经分配的内存中可以容纳多少元素。那是容器在那块内存中总共可以容纳多少元素,而不是还可以容纳多少元素。如果你想知道一个vector或string中有多少没有被占用的内存,你必须从capacity()中减去size()。如果size和capacity返回同样的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的重新分配步骤。
(3) resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会发生重新分配。
(4) reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)

这个简介表示了只要有元素需要插入而且容器的容量不足时就会发生重新分配(包括它们维护的原始内存分配和回收,对象的拷贝和析构和迭代器、指针和引用的失效)。所以,避免重新分配的关键是使用reserve尽快把容器的容量设置为足够大,最好在容器被构造之后立刻进行。

例如,假定你想建立一个容纳1-1000值的vector。没有使用reserve,你可以像这样来做:

vector v;
for (int i = 1; i <= 1000; ++i) v.push_back(i);
在大多数STL实现中,这段代码在循环过程中将会导致2到10次重新分配。(10这个数没什么奇怪的。记住vector在重新分配发生时一般把容量翻倍,而1000约等于210。)

把代码改为使用reserve,我们得到这个:

vector v;
v.reserve(1000);
for (int i = 1; i <= 1000; ++i) v.push_back(i);
这在循环中不会发生重新分配。

在大小和容量之间的关系让我们可以预言什么时候插入将引起vector或string执行重新分配,而且,可以预言什么时候插入会使指向容器中的迭代器、指针和引用失效。例如,给出这段代码,

string s;

if (s.size() < s.capacity()) {
s.push_back(‘x’);
}
push_back的调用不会使指向这个string中的迭代器、指针或引用失效,因为string的容量保证大于它的大小。如果不是执行push_back,代码在string的任意位置进行一个insert,我们仍然可以保证在插入期间没有发生重新分配,但是,与伴随string插入时迭代器失效的一般规则一致,所有从插入位置到string结尾的迭代器/指针/引用将失效。

回到本条款的主旨,通常有两情况使用reserve来避免不必要的重新分配。第一个可用的情况是当你确切或者大约知道有多少元素将最后出现在容器中。那样的话,就像上面的vector代码,你只是提前reserve适当数量的空间。第二种情况是保留你可能需要的最大的空间,然后,一旦你添加完全部数据,修整掉任何多余的容量。

2》使用“交换技巧”来修整vector过剩空间/内存

有一种方法来把它从曾经最大的容量减少到它现在需要的容量。这样减少容量的方法常常被称为“收缩到合适(shrink to fit)”。该方法只需一条语句:vector(ivec).swap(ivec);
表达式vector(ivec)建立一个临时vector,它是ivec的一份拷贝:vector的拷贝构造函数做了这个工作。但是,vector的拷贝构造函数只分配拷贝的元素需要的内存,所以这个临时vector没有多余的容量。然后我们让临时vector和ivec交换数据,这时我们完成了,ivec只有临时变量的修整过的容量,而这个临时变量则持有了曾经在ivec中的没用到的过剩容量。在这里(这个语句结尾),临时vector被销毁,因此释放了以前ivec使用的内存,收缩到合适。

3》用swap方法强行释放STL Vector所占内存

template < class T> void ClearVector( vector& v )
{
    vectorvtTemp;
    vtTemp.swap( v );
}

    vector v ;
    nums.push_back(1);
    nums.push_back(3);
    nums.push_back(2);
    nums.push_back(4);
    vector().swap(v);

/* 或者v.swap(vector()); */

/或者{ std::vector tmp = v;   v.swap(tmp);   }; //加大括号{ }是让tmp退出{ }时自动析构/

5.Vector 内存管理成员函数的行为测试

C++ STL的vector使用非常广泛,但是对其内存的管理模型一直有多种猜测,下面用实例代码测试来了解其内存管理方式,测试代码如下:

#include
#include
using namespace std;

int main()
{
vector iVec;
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //1个元素, 容器容量为1

iVec.push_back(1);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //2个元素, 容器容量为2

iVec.push_back(2);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //3个元素, 容器容量为4

iVec.push_back(3);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //4个元素, 容器容量为4

iVec.push_back(4);
iVec.push_back(5);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //5个元素, 容器容量为8

iVec.push_back(6);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //6个元素, 容器容量为8

iVec.push_back(7);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //7个元素, 容器容量为8

iVec.push_back(8);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //8个元素, 容器容量为8

iVec.push_back(9);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //9个元素, 容器容量为16
/* vs2005/8 容量增长不是翻倍的,如
    9个元素   容量9
    10个元素 容量13 */

/* 测试effective stl中的特殊的交换 swap() */
cout << "当前vector 的大小为: " << iVec.size() << endl;
cout << "当前vector 的容量为: " << iVec.capacity() << endl;
vector(iVec).swap(iVec);

cout << "临时的vector对象 的大小为: " << (vector(iVec)).size() << endl;
cout << "临时的vector对象 的容量为: " << (vector(iVec)).capacity() << endl;
cout << "交换后,当前vector 的大小为: " << iVec.size() << endl;
cout << "交换后,当前vector 的容量为: " << iVec.capacity() << endl;

return 0;
}

6.vector的其他成员函数

c.assign(beg,end):将[beg; end)区间中的数据赋值给c。
        c.assign(n,elem):将n个elem的拷贝赋值给c。
        c.at(idx):传回索引idx所指的数据,如果idx越界,抛出out_of_range。
        c.back():传回最后一个数据,不检查这个数据是否存在。
        c.front():传回地一个数据。
        get_allocator:使用构造函数返回一个拷贝。
        c.rbegin():传回一个逆向队列的第一个数据。
        c.rend():传回一个逆向队列的最后一个数据的下一个位置。
        c.~ vector ():销毁所有数据,释放内存。

7.备注:在用vector的过程中的一些问题,特此列出讨论:

1)

vector  a;

int  b = 5;

a.push_back(b);

此时若对b另外赋值时不会影响a[0]的值

2)

vector <int*> a;
                     int *b;
                     b= new int[4];
                     b[0]=0;
                     b[1]=1;
                     b[2]=2;
                     a.push_back(b);
                     delete b;          //释放b的地址空间
                     for(int i=0 ; i ❤️ ; i++)
                     {
                           cout<<a[0][i]<<endl;
                     }

此时输出的值并不是一开始b数组初始化的值,而是一些无法预计的值.

分析:根据1) 2)的结果,可以想到,在1)中,  往a向量中压入的是b的值,即a[0]=b,此时a[0]和b是存储在两个不同的地址中的.因此改变b的值不会影响a[0];而在2)中,因为是把一个地址(指针)压入向量a,即a[0]=b,因此释放了b的地址也就释放了a[0]的地址,因此a[0]数组中存放的数值也就不得而知了.  
————————————————
版权声明:本文为CSDN博主「hancunai0017」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hancunai0017/article/details/7032383

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中vector用法 的相关文章

随机推荐

  • QSS的使用

    QSS官方文档 https doc qt io qt 5 stylesheet reference html 图标制作例子 normal hover press disable 图标制作 按钮设计指南 按钮多态的几种方法 一 程序应用qss
  • 微信小游戏入门案例——拼图游戏

    微信小游戏入门案例 拼图游戏 涉及内容 canvas组件 小程序界面绘图API 目录结构 pages game game js pages game game js 方块的初始位置 var num 00 01 02 10 11 12 20
  • Python 元组tuple详解(超详细)

    文章目录 Python内置函数 方法详解 元组tuple 1 创建元组 1 1 使用 创建元组 1 2 使用 tuple 函数 创建元组 1 3 元组 单个元素 1 4 元组 VS 列表 2 访问元组 2 1 下标索引访问 2 2 切片访问
  • qt 修改设计师界面ui不生效

    情况描述 我是之前用的vs编译器 编译的文件在代码界面 不喜欢这种方式 想要生成的文件都在一个界面 然后我又换回了MinGW编译器 然后在设计师界面修改了ui 重新编译一直不生效 网上常用两种方法 1 在设置中取消shadow 就会重新编译
  • Linux学习笔记 - Linux的文件目录与属性

    Linux的文件目录与属性 使用者与群组 这里面涉及三个概念 分别为user group other 先讲group 即组的概念 可以理解为一个项目的开发 一个组里面有若干个组员 每个组员负责一个模块的功能开发 大家都能够访问公共部分的代码
  • 数据结构与算法分析——第1~2章考试题

    判断题 1 1 The Fibonacci number sequence FN is defined as F0 0 F1 1 FN FN 1 FN 2 N 2 3 The time complexity of the function
  • Qt Installer Framework打包基础

    一 简介 Qt Installer Framework 简称QIF 提供了一组工具和实用程序来创建支持桌面Qt平台的安装程序 支持Linux Microsoft Windows和macOS操作系统 二 操作步骤 1 编译可执行程序文件 这里
  • 【java】SpringBoot2.X 通过druid-spring-boot-starter集成druid

    1 pom文件
  • 常见的shell命令

    文章目录 常用的shell命令 一 终端的使用 1 打开 2 关闭 3 放大或者缩小 4 在终端上复制 5 关闭当前进程 强制 二 shell命令 所有的命令输入完毕 按回车键执行 1 管理员权限的切换 2 退出管理员 3 临时使用管理员权
  • AIX hacmp oracle9i ORA-32700: error occurred in DIAG Group service

    A HACMP ORALCE9I 现象 一台主机重启后 启动数据库出现ORA 32700 error occurred in DIAG Group service 解决方法 分别重启两台机器上的 hacmp 1 停止hacmp节点 smit
  • 中台战略下的保险订单销售模式设计

    作者在 保险趋势分析与保险中台数字化转型 文章里提到了保险业务系统中台化后保险商品化和订单化的销售模式 本文主要通过购物车 订单中心 微前端以及产品通道等技术手段 对保险企业实施中台战略后的保险订单化销售模式进行设计 形成可实施的方案 微前
  • Qt5学习笔记(6)——下拉列表框QComboBox类

    最近需要做一个地址选择下拉列表 如下图 QComboBox下拉列表用法还是比较简单的 常用方法和属性 1 addItems void addItems const QStringList texts 在QComboBox的最后添加一项 2
  • [ASP.NET]谈谈IIS与ASP.NET管道

    ASP NET 谈谈IIS与ASP NET管道 作为一个Asp Net平台开发者 非常有必要了解IIS和Asp Net是如何结合 执行我们的托管代码 以及Asp Net管道事件的 本节目录 IIS 5 X IIS 6 IIS 7 集成模式
  • 复旦微FM33LG048芯片使用(5)UART3数字外设的使用,引脚重映射

    uart3的引脚配置比较特殊 先要配置 GPIO InitStruct mode FL GPIO MODE DIGITAL 配置为数字外设 什么是数字外设 根据文档里描述 也就是配置了数字外设 引脚的输出输入由使用的外设决定 不需要我们配置
  • 什么是数据仓库?数据仓库的特点与架构演进

    1 为什么需要数据仓库 在没有数仓之前我们做数据分析到报表展示 依赖的都是从业务数据库中取数据来做分析 业务数据库主要是为业务操作服务 虽然可以用于分析 但需要做很多额外的调整 会存在以下几个问题 表结构关联关系错综复杂 业务数据库通常是根
  • js七牛云下载视频、音频、pdf、图片

    近期碰到一个需求 浏览器下载视频 音频等附件 原生组件video audio倒是支持下载 但是别的类型不行 而且无法通过下载按钮进行 常规下载思路使用a标签download属性下载附件 但是浏览器兼容性不好 而且针对视频 音频 pdf等浏览
  • C# 下载服务器的文件

    C 下载服务器的文件方法 带下载进度条 来源 C 下载文件并显示显示进度的方法实现 光脚丫思考的专栏 CSDN博客 float percent 0 try System Net HttpWebRequest Myrq System Net
  • C语言练习:通讯录

    通讯录代码 本文介绍如何使用C语言实现一个通讯录的功能 1 通讯录能存放1000个人的信息 每个人信息包含名字 年龄 性别 电话 地址 2 增加人的信息 3 删除指定人信息 4 查找指定人的信息 5 修改指定人的信息 通讯录包含三个部分 头
  • JS插件:粒子动画

    1 canvas nest js 配置参数 2 particle js 安装导入 特定参数项 配置参数 JSON格式 3 Particleground js 安装导入 配置参数 1 canvas nest js 轻量 只有1 6 kb 只能
  • C++中vector用法

    vector 向量 C 中的一种数据结构 确切的说是一个类 它相当于一个动态的数组 当程序员无法知道自己需要的数组的规模多大时 用其来解决问题可以达到最大节约空间的目的 用法 1 文件包含 首先在程序开头处加上 include以包含所需要的