当前位置: 首页 > article >正文

C++《vector》

#1024程序员节|征文#

在之前C++《string》当中我们学习了string的各个接口的使用以及在string模拟实现当中试着实现了string当中日常我们会较为频繁使用到的接口,通过模拟实现我们对string的底层有了更深层次的理解。接下来在本篇当中我们将进行进行STL的学习,在本篇我们要学习的容器是vector也就是之前在数据结构学习过的顺序表,在学习vector过程中由于STL的接口大部分都是相识的因此在学习完string后学习vector将会轻松许多。在了解vector过程中最重要的是要了解深浅拷贝,这部分的内容将在本篇之后的vector模拟实现当中重点来讲解。接下来就开始本篇的学习吧!!!


1.构造函数

vector::vector - C++ Reference

在vector当中构造函数提供了以上的4个接口,这其中包括一个拷贝构造函数,接下来我们就来一一了解这些接口该如何使用

在了解vector的构造之前先要了解的是STL当中的vector是用模板实现的,这样是为了vector内的数据类型不被限定死,这样创建的vextor对象内的数据类型就可以根据用户显示写大的来确定

在vector构造函数的接口当中以下几个是和我们之前学习的string类似的

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	//无参构造
	vector<int> v1;
	//一个元素构造
	vector<int> v2(1);
	//n个一样的元素构造
	vector<int> v3(5, 6);

	return 0;
}

接下来要了解的两个接口就不和之前学习的string不同

template <class InputIterator>
vector (InputIterator first, InputIterator last,const allocator_type& alloc =allocator_type());

以上这个接口是使用迭代器区间来实现vector对象的初始化构造,在此迭代器fist是输入的开始,last迭代器是结束位置,最终范围是 [first,last),该区间是左闭右开的,构造的过程中不包括last指向的值

使用例如以下示例

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	//无参构造
	vector<int> v1;
	//一个元素构造
	vector<int> v2(1);
	//n个一样的元素构造
	vector<int> v3(5, 6);
    //使用迭代器区间来构造
	vector<int> v4(v3.begin(), v3.end()-1);
	
	return 0;
}

在以上代码中对象v4的初始化就是使用迭代器区间来实现,在此开始时从v3.begin(),结束位置是v3.end(),并且最后的数据不包括v3.end()位置的元素 

因此v4初始化之后该对象内部数据就为6 6 6 6 

在此我们还要了解vector初始化的方式是通过调用initializer_list来完成初始化,这个接口是在C++11之后支持的

要了解这个构造的接口是如何实现的我们就要先来了解initializer_list是什么

initializer_list是一个C++11当中增加的,在此我们可以认为将一系列的数据使用{}括起来就会初始化出一个对象,该对象的类型就是initializer_list。可以认为initializer_list也是一个容器

 

在initializer_list当中成员函数非常的简单,就支持迭代器和size

在了解了initializer_list之后我们就可以知道在vector构造当中提供的initializer_list接口就可以实现用户直接将使用{}括起来的数据直接给vector对象来实现初始化构造,在该过程其实可以理解为会在底层开出一块内存空间将{}内的数据存储到内存空间内,并且还会有两个指针分别指向空间的起始和终止位置,最后将该空间内的数据依次插入到vector对象内实现初始化

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v5({ 1,2,3,4 });
	vector<int> v6 = { 1,2,3,4 };


	return 0;
}

在以上代码中对象v5就是通过调用vector构造函数当中的initializer_list接口来直接完成构造。而对象v6其实语法逻辑和v5有所不同的是通过隐式类型转换,是将initializer_list对象先构造出一个vector的临时对象之后再去拷贝构造,但编译器在这样的连续构造+拷贝构造就会演化为直接构造

接下来了解vector当中的拷贝构造函数

vector(const vector& x)就是将对象x的拷贝数据拷贝给新创建的对象,在此过程进行的是深拷贝,具体实现在之后的vector模拟实现章节会进行解析

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v6 = { 1,2,3,4 };
	vector<int> v7(v6);

	return 0;
}

以上代码就是使用对象v6来拷贝构造v7

2.析构函数

vector::~vector - C++ Reference

 在vector当中也提供了析构函数,该函数会在对象销毁时自动调用,不需要我们显示的调用

3.赋值运算符重载

vector::operator= - C++ Reference

在vector当中也提供了赋值运算符重载函数,有了这个函数我们就可以将两个已经初始化的vector对象之间进行赋值

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	//无参构造
	vector<int> v1;
	//一个元素构造
	vector<int> v2(1);
	v1 = v2;

	return 0;
}

以上就在对象v1和v2在初始化之后将对象v2赋值给v1

4.容量操作

在vector当中容量的操作除了以下讲解的其实还有其他的操作,但其他的函数操作在日常当中的使用较少,并且这些函数和之前我们学习string时类似,因此你如果想详细了解可以观看以下文档

vector - C++ Reference

4.1 size

在vector类当中也提供了size这个函数来得到对象内的有效元素个数

4.2 capacity

在vector类中的capacity函数是用来得到类对象当中的空间大小也就是容量 

4.3 resize

在vector类当中也提供了resize来将对象内的有效元素个数改为指定值n,这时就会出现以下三种情况

1.此时的有效数据个数比n大,那么调用resize之后就会将原有效数据个数截断到n个
2. 此时的有效数据个数比n小,并且n比当前的内存空间大小小,那么这时调用resize就会将对象当中从原有效数据之后到n个元素都使用指定值val来填充
3..此时的当前的内存空间大小比n小,那么这时调用resize就会先将该对象进行内存空间的扩容之后再进行以上的2操作

4.4 reserve

在vector类当中也提供了reserve来实现将对象的内存空间扩容到指定值n,当n大于原空间大小时会进行扩容,但当n小于原空间的大小时一般不会进行缩容

5. 访问以及遍历操作

5.1 下标+[ ]

vector::operator[] - C++ Reference

在vector当中由于底层和顺序表类似物理空间是连续的因此能通过下标+[ ]的方式来访问vector对象内的元素,并且和string一样也提供了const对象和非const对象两个接口。对于非const对象来说使用下标+[ ]访问元素既可读也可以写;但对于const对象来说使用下标+[ ]访问元素只能读

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{

	vector<int> v3(5, 6);

	for (int i = 0; i < v3.size(); i++)
	{
		cout << v3[i] << " ";
	}


	return 0;
}

5.2 迭代器

在vector类当中和string一样也提供了正向迭代器和 反向迭代器,并且以上迭代器都提供了const接口和非const接口

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v5({ 1,2,3,4 });

	//vector<int>::iterator i1 = v5.begin();
	auto i1 = v5.begin();
	while (i1 != v5.end())
	{
		cout << *i1 << " ";
		i1++;
	}
	cout << endl;

	auto i2 = v5.rbegin();
	while (i2 != v5.rend())
	{
		cout << *i2 << " ";
		i2++;
	}
	cout << endl;


	return 0;
}

5.3 范围for

在vector当中由于支持迭代器那么就可以支持范围for来遍历对象内的元素

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v6 = { 1,2,3,4 };

	for (auto x : v6)
	{

		cout << x << " ";
	}

	return 0;
}


6.修改操作

在vector提供了以下的函数来实现对对象内数据的修改

以上两个函数emplace和emplace_back是string中没有的,在此在本篇当中先不讲这两个函数该如何使用,这两个函数list当中也是有的因此将在list篇章中细致的讲解

6.1 assign

vector::assign - C++ Reference

在vector当中也支持assign将原vector对象内的数据进行重覆盖,在此和string不同的是在调用这个接口需要传的是迭代器区间

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v5({ 7,8,9,10 });
	vector<int> v6 = { 1,2,3,4 };

	for (auto x : v6)
	{

		cout << x << " ";
	}

	return 0;
}

6.2 ⭐push_back与pop_back

在vector当中提供 push_back与pop_back两个函数分别来实现尾插和尾删

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v6 = { 1,2,3,4 };

	v6.pop_back();
	v6.push_back(88);
	v6.push_back(99);

	for (auto x : v6)
	{

		cout << x << " ";
	}

	return 0;
}

6.3 insert和erase

vector::insert - C++ Reference

vector::erase - C++ Reference

在vector当中也提供了insert和erase来实现任意位置的插入和删除

在此的插入和删除要传的参数和之前string有所不同,vector中的inser和erase需要传的是迭代器区间或者是一个迭代器

例如以下示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v5({ 7,8,9,10 });
	vector<int> v6 = { 1,2,3,4 };

	v6.insert(v6.begin(), 999);
	v6.insert(v6.begin()+1,2, 888);
	v6.erase(v6.end() - 1);
	v6.erase(v6.end() -3, v6.end() - 1);

	for (auto x : v6)
	{

		cout << x << " ";
	}


	return 0;
}

注意:在使用迭代器区间删除时,删除区间是左闭右开的,删除不包括最后位置的值
 



 

以上就是vector使用的介绍,通过本篇讲解你会发现string和vector内大部分的函数都是相识的,因此在学习了string之后再了解vector就任意多了,这是因为STL大部分都是相通的,学习了一个容器之后后面的容器的使用就较为任意上手了。
本篇的内容到这里就结束了,接下来再下一篇vector模拟实现当中我们将会来试着自己实vector,在这个过程当中会了解到vector迭代器失效这个在vector非常重要的知识点,未完待续……

 


http://www.kler.cn/news/366134.html

相关文章:

  • Python 从入门到实战39(线程间的通信)
  • 鸿蒙实现相机拍照及相册选择照片
  • 设计模式: Pimpl(Pointer to Implementation)
  • 【D3.js in Action 3 精译_037】4.1 DIY 实战:D3 源码分析之——d3.timeFormat() 函数
  • Android13、14特殊权限-应用安装权限适配
  • 为Windows Terminal 配置zsh + Oh-My-Zsh!
  • 【实战案例】Django框架使用模板渲染视图页面及异常处理
  • Vscode连接WSL2(Ubuntu20.04)
  • P2818 天使的起誓
  • Linux: network: wireshark IO图的一个问题
  • Matlab学习02-matlab中的数据显示格式及符号变量
  • Flask-SQLAlchemy 组件
  • 排序算法 —— 直接选择排序
  • 在 Vue 渲染模板时,如何保留模板中的 HTML 注释?
  • 界面控件DevExpress WPF中文教程:Data Grid——表格视图概述
  • 家政服务管理系统小程序ssm+论文源码调试讲解
  • hiveserver与beeline
  • 【Linux 从基础到进阶】实时性能监控与调优(Prometheus、Grafana)
  • PL/I语言的起源?有C语言,有B语言和A语言吗?为什么shell脚本最开始可能有#!/bin/bash字样?为什么不支持嵌套注释?
  • 机器学习与深度学习的分类
  • 大数据治理平台建设规划方案(71页WORD)
  • opencv - py_photo - py_non_local_means 非局部均值去噪
  • LinkedList和链表之刷题课(上)
  • STM32--TIM编码器接口
  • 从区别看本质:CRM和SCRM的全面对比
  • 江协科技STM32学习- P21 ADC模数转换器