vector介绍和基本使用

2023-05-16

文章目录

  • 一.vector介绍
  • 二.vector使用
    • (1).constructor
    • (2).iterator
    • (3).capacity
    • (4).Element access
    • (5).Modifiers
  • 三.vector迭代器失效问题

一.vector介绍

vector文档

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

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

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

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

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

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

二.vector使用

(1).constructor

(1).构造一个空容器,没有元素

vector<int> v1;

(2).构造n个值为val的容器

vector<int> v2(10,2); // size为10,capacity为10

(3).使用 [first,last) 区间内的元素构造容器

vector<int> v3(v2.begin(),v2.end());
string s = "hello world";
vector<char> v4(s.begin(),s.end());

(4).拷贝构造

vector<int> v5(v3);

(2).iterator

iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

在这里插入图片描述

#include<iostream>
#include<vector>
using namespace std;
void print(const vector<int>& v)
{
	// const_iterator
	vector<int>::const_iterator vit = v.begin();
	while (vit != v.end())
	{
		cout << *vit << " ";
		++vit;
	}
	cout << endl;
}
int main()
{
	vector<int> v1(10, 2);
	const vector<int> v2(10,5);
	
	vector<int>::iterator vit = v1.begin();
	while (vit != v1.end())
	{
		cout << *vit << " ";
		++vit;
	}
	cout << endl;

	print(v2);
	// reverse_iterator
	vector<int>::reverse_iterator vrit = v1.rbegin();
	while (vrit != v1.rend())
	{
		cout << *vrit << " ";
		++vrit;
	}
	cout << endl;
	// const_reverse_iterator
	vector<int>::const_reverse_iterator vrit2 = v2.rbegin();
	while (vrit2 != v2.rend())
	{
		cout << *vrit2 << " ";
		++vrit2;
	}
	cout << endl;
}

(3).capacity

(1). size_t size()const;

返回容器中有效的元素个数

(2). size_t capacity()const;

返回当前容器的容量

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v(10,2);
	cout<<v.size()<<endl; // 返回有效数据的个数
	cout<<v.capacity()<<endl;// 返回容量的个数
	return 0;
}

(3).void resize (size_t n, T val = T());

1). 当 n 小于容器当前的size,size减少到 n
2). 当 n 大于容器当前的size,小于容器当前的 capacity,size扩充到n,值用val填充
3). 当 n 大于容器当前的capacity,先扩容,再将容器的size扩充n,值用val填充

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	// vs2019下的测试结果,不同编译器的结果可能不同
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5); // size = 5,capacity = 6

	v.resize(2);    // size = 2,capacity = 6
	v.resize(6, 2); // size = 6,capacity = 6
	v.resize(8,3);  // size = 8,capacity = 9
}

(4).void reserve(size_t n);

1). 当n大于容器当前的capacity时,将capacity扩大到n或更大。
2). 当n小于容器当前的capacity时,什么也不做。

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5); // size = 5,capacity = 6
	v.reserve(10);  // size = 5,capacity = 10
	v.reserve(6);   // size = 5,capacity = 10
}

注意 :

1). capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。不要固化的认为,顺序表增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

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

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

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	size_t sz;
	vector<int> foo;
	sz = foo.capacity();
	cout << "making foo grow:" << endl;
	for (int i = 0; i < 100; ++i) {
		foo.push_back(i);
		if (sz != foo.capacity()) {
			sz = foo.capacity();
			cout << "capacity changed: " << sz <<endl;
		}
	}
}
//vs:运行结果:
//making foo grow :
//capacity changed : 1
//capacity changed : 2
//capacity changed : 3
//capacity changed : 4
//capacity changed : 6
//capacity changed : 9
//capacity changed : 13
//capacity changed : 19
//capacity changed : 28
//capacity changed : 42
//capacity changed : 63
//capacity changed : 94
//capacity changed : 141
//g++运行结果:
//making foo grow :
//capacity changed : 1
//capacity changed : 2
//capacity changed : 4
//capacity changed : 8
//capacity changed : 16
//capacity changed : 32
//capacity changed : 64
//capacity changed : 128

(5).bool empty()const;

判断当前容器是否为空

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v(10, 2);
	cout << v.empty() << endl;
	return 0;
}

(4).Element access

(1).

reference operator[] (size_t n);
const_reference operator[] (size_t n) const;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v(10, 1);
	//使用“下标+[]”的方式遍历容器
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;
	return 0;
}

(2).

reference at (size_type n);
const_reference at (size_type n) const;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v(10, 1);
	//使用“下标+[]”的方式遍历容器
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v.at(i) << " ";
	}
	cout << endl;
	return 0;
}

operator[] 和 at() 的区别

operator[] 和 at() 的区别
operator[] 和 at() 的区别

(5).Modifiers

(1).void push_back (const T& val);
(2).void pop_back();

通过push_back函数对容器进行尾插,pop_back函数对容器进行尾删。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(1); //尾插元素1
	v.push_back(2); //尾插元素2
	v.push_back(3); //尾插元素3
	v.push_back(4); //尾插元素4

	v.pop_back(); //尾删元素
	v.pop_back(); //尾删元素
	v.pop_back(); //尾删元素
	v.pop_back(); //尾删元素
	return 0;
}

(3). insert 和 erase

iterator insert (iterator position, const value_type& val);
void insert (iterator position, size_type n, const value_type& val);
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
[first,last)
iterator erase (iterator position);
iterator erase (iterator first, iterator last); 
[first,last)
#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v1;
	v1.insert(v1.begin(),1);
	v1.insert(v1.end(),5,2);
	print(v1);
	vector<int> v2;
	v2.insert(v2.begin(),v1.begin(),v1.end());
	print(v2);

	v2.erase(v2.begin());
	v2.erase(v2.begin(),v2.begin() + 2);
	print(v2);
}

(4). void swap (vector& x);

通过swap函数可以交换两个容器的数据空间,实现两个容器的交换

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v1(10,1);
	vector<int> v2(10,2);
	v1.swap(v2);
	print(v1);
	print(v2);
}

以上是按位置进行插入或删除元素的方式,若要按值进行插入或删除(在某一特定值位置进行插入或删除),则需要用到find函数。

find函数 :

template <class InputIterator, class T>
   InputIterator find (InputIterator first, InputIterator last, const T& val);

find函数共三个参数,前两个参数确定一个迭代器区间(左闭右开),第三个参数确定所要寻找的值。
find函数在所给迭代器区间寻找第一个匹配的元素,并返回它的迭代器,若未找到,则返回所给的第二个参数。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	
	vector<int>::iterator pos = find(v.begin(),v.end(),3);
	if (pos != v.end())
	{
		v.insert(pos,30);
	}
	pos = find(v.begin(), v.end(), 3);
	v.erase(pos);
}

(5). void clear();

使容器的 size 成为 0

三.vector迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

实例一 : 迭代器的意义改变
(vs2019下报错,g++下不报错,因为不同编译器处理不同,但程序都是不对的)
原意是想要删除3,但由于我们插入了30,pos指向了30,迭代器的意义改变。
解决方案 : 重新定位pos的位置

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);//  size = 5,capacity = 6
	
	vector<int>::iterator pos = find(v.begin(),v.end(),3);
	if (pos != v.end())
	{
		v.insert(pos,30);
	}
	print(v);
	// 解决方案
	//pos = find(v.begin(),v.end(),3);
	v.erase(pos);
	print(v);
}

实例二 : 迭代器成为野指针
(vs2019和g++都报错)

在插入之前容器已满,再插入元素会增容(新开一块空间,拷贝数据,释放原空间),释放掉原空间后,pos成为了野指针

解决方案 : 重新定位pos的位置

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6); // size = 6,capacity = 6
	
	vector<int>::iterator pos = find(v.begin(),v.end(),3);
	if (pos != v.end())
	{
		 v.insert(pos,30);
	}
	print(v);
	// 解决方案
	// pos = find(v.begin(),v.end(),3);
	v.erase(pos);
}

实例三 : 删除偶数
(vs2019无论最后一个数是奇数还是偶数,程序都会崩溃,因为erase()以后vit迭代器已经失效,对失效的迭代器进行++操作导致程序崩溃,g++下最后一个数是偶数会崩溃,因为最后进行erase()时,进行了越界访问,g++下最后一个数是奇数不会崩溃,但如果出现连续的偶数时,程序运行结果依然是错误的)

解决方案 : 利用 erase() 的返回值,erase() 返回删除元素的下一个有效位置

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	// 删除偶数
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	v.push_back(7);

	vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		if (*vit % 2 == 0)
			v.erase(vit);
		++vit;
	}
	
	// 解决方案
	vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		if (*vit % 2 == 0)
			vit = v.erase(vit);
		else
			++vit;
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vector介绍和基本使用 的相关文章

  • 是否应该始终使用 boost::ptr_vector 代替 std::vector ?

    这只是我遇到的一个概念性问题 在我当前的项目中 感觉我过度使用了 boostsmart ptr and ptr container图书馆 我正在创造boost ptr vectors在许多不同的对象中 并调用 Transfer 方法从一个对
  • 检查向量索引是否为空

    在我的代码中 我需要这样做 if edges j ConnectedToNode i problem line edges push back Edge i j nodes i Position nodes j Position dista
  • 返回填充有局部变量的向量是否安全?

    返回一个充满局部变量的向量是否安全 例如 如果我有 include
  • 大数组的堆栈溢出,但同样大的向量的堆栈溢出?

    今天我在处理大型数据结构时遇到了一个有趣的问题 我最初使用向量来存储超过 1000000 个整数 但后来决定我实际上并不需要向量的动态功能 无论如何 我在声明后就保留了 1000000 个位置 相反 这将是有益的 能够在数据结构中的任何位置
  • 使用shared_ptr的例子?

    你好 我今天问了一个关于如何在同一个向量数组中插入不同类型的对象 https stackoverflow com questions 3475030 different types of objects in the same vector
  • 使用 3 维向量的问题

    如何在 C 中使用 3 维向量 vector
  • 用 t 个随机数生成位向量

    我想生成一个数组 向量v大小的p with t那些和p t零 的位置t ones must是随机的 这是我迄今为止编写的解决方案 但我不确定它是否是最有效的解决方案 另外我从来没用过random device or mt19937 找到他们
  • 计算结构向量中的匹配项

    我有一个问题 要求我计算该数组中使用以下任一方法的实例的数量std count or std find 我知道如何使用标准数据 参见底部代码 类型来执行此操作 但不知道如何使用NameContainer我正在使用的 Type struct
  • 如何使用类初始化 STL 向量/列表而不调用复制构造函数

    我有一个 C 程序 它使用包含类实例的 std list 如果我打电话 例如myList push back MyClass variable 它经历创建临时变量的过程 然后立即将其复制到向量 然后删除临时变量 这远没有我想要的那么高效 而
  • STL:为向量编写“where”运算符

    我需要根据几个布尔谓词找到向量中的索引 ex vector
  • SVG/矢量图室内导航路由

    我一直在网上搜索有关如何为基于 SVG 的室内平面图实现我自己的点对点导航系统的教程或方法 我已经在网上搜索过 但唯一的选项适用于谷歌地图 不过 我使用 Illustrator 创建了地图 并使用路径 矢量作为 SVG 图像 我不需要为用户
  • 如何让 SWIG 在包装包含向量的模板类时应用模板?

    我正在尝试使用 SWIG 来包装 在 C 中 一些 C 代码 该代码包含一个模板类 该模板类本身包装了std vector
  • 释放指针向量,但内存仍在使用中

    我不知道下面的代码有什么问题 我正在删除所有指针 但是当我使用 top 命令查看内存时 我可以看到仍然有大量内存分配给程序 我在这里缺少一些东西来释放内存吗 include
  • 如何旋转矢量?

    如果我有 1 0 我旋转它90 degrees 1 2PI radians 我应该得到 0 1 我该如何实现这一目标 我在看这一页 http en wikipedia org wiki Rotation matrix并实现了这个 var r
  • 如何在 C 中将向量参数传递给 OpenCL 内核?

    我在将向量类型 uint8 参数从 C 中的主机代码传递到 OpenCL 内核函数时遇到问题 在主机中 我将数据存储在数组中 cl uint dataArr 8 1 2 3 4 5 6 7 8 我的真实数据不仅仅是 1 8 这只是为了便于解
  • Three.js 设置并读取相机外观向量

    而不是使用camera rotation或lookAt 函数旋转相机 我想将外观矢量直接传递给相机 是否可以直接设置相机外观矢量以及是否可以从相机读取外观矢量 相机没有 外观矢量 因此无法设置它 但是 您可以构造一个point通过将您的外观
  • 一个同时接受 std::vector 和 QVector 的函数模板?

    假设我有一个函数叫做loadData 它需要一个容器 填充数据 和一个 CSV 文件 我需要以下重载 loadData std vector
  • 添加到 std::vector 的中间

    有没有办法将值添加到 a 的中间vector在 C 中 假设我有 vector
  • C# 等价于 C++ 向量或双端队列

    我几乎可以肯定这应该是重复的 但我搜索了一段时间但找不到答案 我应该在 C 中使用什么来替换 C 向量和双端队列有效率的 也就是说 我需要一种有效支持直接索引的结构 并且还支持以有效的方式再次从一端或两端删除 取决于向量或双端队列的情况 在
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维

随机推荐

  • 在ubuntu下安装vmware-tools

    用vmware虚拟机安装了ubuntu之后 xff0c 为了实现更加强大的功能 xff0c 比如说直接从windows主机拖文件进入ubuntu xff0c 以及加强ubuntu的性能 xff0c 我们一般都要安装vmware tools
  • 虚拟机安装Ubantu 16.04,并修改配置文件更改网络配置

    https blog csdn net qq 41016818 article details 81211744 ops request misc 61 amp request id 61 amp biz id 61 102 amp utm
  • Ubuntu 16.04下安装visual studio code

    一 坑和解决办法 很多帖子上写的方法都是使用命令方式 xff1a 1 先安装make sudo add apt repository ppa ubuntu desktop ubuntu make sudo apt get update su
  • 虚拟机Ubuntu与外网连接

    详情可参考 xff1a https blog csdn net gaoganghua article details 80386107 ops request misc 61 257B 2522request 255Fid 2522 253
  • Xftp6如何连接虚拟机(Ubuntu)Windows与虚拟机之间传输文件

    一 安装Ubuntu ssh出现异常 Err 1 http security ubuntu com ubuntu xenial security main amd64 openssh sftp server amd64 1 7 2p2 4u
  • ubuntu下搭建ftp服务器

    1 安装vsftpd xff0c 安装命令 xff1a sudo apt get install vsftpd 查看是否安装成功 xff1a vsftpd version 2 新建一个文件夹用于FTP的工作目录 xff08 cpucard是
  • 命名空间 std 中没有名为 stoi 的成员

    我正在测试std stoi以下链接中的函数 xff1a 但我收到了错误 xff1a 已经添加了头文件 include lt string gt xff0c 但仍然错误提示 xff1a 在命名空间 std 中没有名为 stoi 的成员 xff
  • Linux+vscode 客户端通过代码操作远程服务器端数据库(MySQL)

    这篇文章解决两个问题 xff1a 1 在Linux系统下使用vscode用C C 43 开发客户端程序时 xff0c 如何调用mysql库函数 xff1b 2 客户端与远程服务器端的MySQL连接时 xff0c 需要做哪些前期准备工作 xf
  • put操作提示 No such file or directory

    https blog csdn net weixin 33875839 article details 86128344
  • IDEA导入lib目录下的jar包

    https blog csdn net u010286027 article details 85248719 ops request misc 61 amp request id 61 amp biz id 61 102 amp utm
  • MIPS、ARM、X86三大架构

    MIPS ARM X86三大架构 RISC平台的发展已经有长达几十年的历史了 其最早诞生于80年代的MIPS主机 xff0c 随着技术的不断发展 xff0c RISC平台的应用领域逐步扩展 xff0c 小到手机 xff0c 大到工控设备都可
  • 报错:Diamond types are not supported at language level ‘6‘

    在编译时报错 xff1a 这主要是1 6版本的javac exe编译器不支持菱形运算符 xff1b 解决办法 xff1a 1 修改设置settings和项目结构Project Structure中的JDK版本设置 配置IDEA编译器版本 2
  • Ubuntu18.04.3虚拟机安装步骤

    Ubuntu18 04 3虚拟机安装步骤 xff08 图文教程 xff0c 非常详细 xff01 xff01 xff01 xff09 丶无殇的博客 CSDN博客 ubuntu18虚拟机安装
  • 信号包络

    将一段时间长度的高频信号的峰值点连线 xff0c 就可以得到上方 xff08 正的 xff09 一条线和下方 xff08 负的 xff09 一条线 xff0c 这两条线就叫包络线 包络线就是反映高频信号幅度变化的曲线 对于等幅高频信号 xf
  • 归一化函数normalize详解

    opencv 2 归一化函数normalize详解 1 归一化定义与作用 归一化 就是要把需要处理的数据经过处理后 xff08 通过某种算法 xff09 限制在你需要的一定范围内 首先归一化是为了后面数据处理的方便 xff0c 其次是保证程
  • 多态性之编译期多态和运行期多态(C++版)

    多态性之编译期多态和运行期多态 C 43 43 版 C 43 43 中最为经典的就是多态性 xff0c 多态性充分体现了面向对象的思想 xff0c 并且是C 43 43 与C的最大区别之一 多态性分为编译期多态和运行期多态 xff0c 也称
  • SVM 原理详解,通俗易懂

    看了该作者的文章 xff0c 瞬间膜拜了 xff01 讲得太好了 xff01 转自 xff1a http www blogjava net zhenandaci category 31868 html xff08 一 xff09 SVM的简
  • 线阵相机学习笔记(一)

    1 GigE Vision GigE Vision是由自动化影像协会AIA Automated Imaging Association 发起指定的一种基于千兆以太网的图像传输的标准 具有传输距离长 xff08 无中继时100米 xff09
  • 如何做一个软件项目经理? ----写给公司所有的开发人员

    第一部分 xff1a 软件项目经理的要求 首先是一个管理者 xff0c 其次熟悉某些工具 xff0c 某几种语言 xff0c 行业背景 xff0c 项目管理技能 软件项目经理面临的恶劣环境 xff0c 我们绝大部分软件企业运行在相对混乱的状
  • vector介绍和基本使用

    文章目录 一 vector介绍二 vector使用 1 constructor 2 iterator 3 capacity 4 Element access 5 Modifiers 三 vector迭代器失效问题 一 vector介绍 ve