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

STL之vector容器

vector的介绍

1.vector是可变大小数组的容器

2.像数组一样,采用连续的空间存储,也就意味着可以通过下标去访问,但它的大小可以动态改变

3.每次的插入都要开空间吗?开空间就要意味着先开临时空间,然后在拷贝旧的到新的上面,在释放原来的,就时间而言,这是一个相对代价很高的任务;显然这是不行的,vector的分配策略:会分配一些而外的空间以适应可能的增长,例如我们平时说的以1.5或者2倍的方式增容,不同的库选择不同的策略权衡空间的使用和重新分配,以至于在插入一个元素时能在常数时间内插入;

vector的使用

构造函数:

 

注意:这里的allocator_type是空间配置器,与内存池相关,可以暂时忽略

          这里的vector<int>要传模板,指明你每个元素里面存的类型是什么 

第一个能构造一个空的vector数组

第二个能构造4个元素,每个元素里面存100的数组

第三个传迭代器能根据迭代器构造出一个对象

第四个是拷贝构造函数 

如果第二个中我没有指定每个元素为100,它会根据你传的模板是什么初始化为啥,例如你传int就初始化为0

3种遍历方式

1.operator[]

因为底层是数组,所以重载了operator[]方便遍历

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

2.迭代器遍历

 

 可以看到vector容器提供了begin/end和rbegin/rend,这说明我们可以正反向遍历 

vector<int>::iterator it=vt.begin();
while(it!=vt.end())
{cout<<*it;it++;
}vector<int>::reverse_iterator rit=rbegin();
while(it!=rbegin())
{cout<<*it;it++;
}

3.返回for遍历:底层就是迭代器,只要能实现迭代器就能实现范围for

for(auto&e:vt)
{cout<<e;
}

注意:如果你有一个函数,例如打印函数,你是不想修改数组里面元素的值,那传参时需要传const修饰的数组,此时你在打印函数中使用迭代器,只能用const迭代器 

迭代器分两个版本,一个是const迭代器一个是普通迭代器

void Print(const vector<int>&vt)
{vector<int>::const_iterator it=vt.begin();while(it!=vt.end())
{
cout<<*it;
*it+=1;//这句是错的,你传了const就意味着你不能通过迭代器去修改
}
}

 capacity函数接口

size():顾名思义就是返回数组的大小,这里的大小是有效元素的大小

capacity():是返回这里数组的容量,也就是你动态开辟出来的大小

empty():判断是否为空;如果没有元素即返回true,有就返回false

resize():改变数组的size

reserve():改变数组的容量,如果提前知道空间可以减少增容的代价

注意:vs2022是以1.5倍增长,gcc是以两倍增长,两个用的STL版本不一样,vs使用PJ版本,gcc是用SGI版本

Modifiers函数接口

数组当然实现的是尾插和尾删,效率高,如果你有头插和头删最好别选vector(后面会介绍list和vector的优缺点)

push_back():尾插一个数据

pop_back():尾删一个数据

insert():任意位置的插入,在pos位置之前插入

注意:这里传迭代器 

erase():任意位置的删除,删除pos位置的元素,返回下一个元素的迭代器

注意:这里我们不知道要删除的元素的位置该如何找到呢?vector没有实现find

可以调用<algorithm>库实现的find

找到返回pos位置的迭代器,找不到返回end();

 swap():交换两个vector的数据空间

clear():清空元素,但开辟的空间没有释放

 重点谈迭代器失效问题

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

第一种情况:

如果你先定义了迭代器vector<int>::iterator it=vt.begin();

然后在进行各种扩容操作reserve,resize,insert,assign,push_back等

然后在使用迭代器,那原来的指针it指向的的那块空间已经被释放了,因为你进行了扩容开辟了新空间,你在使用迭代器去解引用或者it!=vt.end()等操作都可能会造成程序崩溃

第二种情况:

比如你使用库实现的find去查找某个元素,会返回一个迭代器类型,然后在释放这个位置的元素

vector<int>::iterator pos=find(vt.begin(),vt.end(),3);
if(pos!=vt.end())
{erase(pos);
}
cout<<*pos<<;//此处会导致非法访问

erase删除pos位置之后,pos位置之后的元素会往前挪动,没有导致底层空间的改变,理论上讲迭代器是不会失效的,但是,如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,pos就会失效,因此删除vector中任意位置的元素是,vs就认为该位置迭代器失效了 

动态二维数组的理解:

我们如何创建一个二维数组,可以想象每个vector的元素都是一个vector<int>

vector<vector<int>> vv(5);

这里可以想象一个一维数组,有五个元素,每个元素都是一个vector<int> 

那我们如何初始化呢 

 第一种:我们学过vector<int> v(3,5)//这是创建3个元素,每个元素都是5,因此我们可以这与初始化二维数组,rows是行,每个元素是vector<int>(cols),initial)

int main() {// 定义二维数组的行数和列数int rows = 3;int cols = 4;// 初始值int initialValue = 0;// 创建并初始化二维 vectorstd::vector<std::vector<int>> twoDArray(rows, std::vector<int>(cols, initialValue));// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

第二种:

可以创建好二维数组,在用循环依次填入数据 


int main() {// 定义二维数组的行数和列数int rows = 3;int cols = 4;// 初始值int initialValue = 0;// 创建空的二维 vectorstd::vector<std::vector<int>> twoDArray;// 逐行添加元素for (int i = 0; i < rows; ++i) {std::vector<int> row(cols, initialValue);twoDArray.push_back(row);}// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

 第三种:使用c++11的初始化列表进行初始化

int main() {// 使用列表初始化创建二维 vectorstd::vector<std::vector<int>> twoDArray = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

注意:当我们创建好了之后,可以像一个二维数组一样使用vv[i][j]去访问每个元素

实质就是operator[]重载运算符,第一个[]先和vv结合,第二个后结合就可以访问了 

 简单模拟实现vector容器、

我已经把代码上传gitee,有需要可以自己拿

 June: 这里包含我的c++和Linux及数据结构https://gitee.com/taifanshu/day2.git

http://www.xdnf.cn/news/3402.html

相关文章:

  • MySQL 索引不生效的情况
  • 【Linux】Linux基础概念
  • 树状数组 + 线段树
  • Java学习手册:Spring Security 安全框架
  • 多模态人工智能研究:视觉语言模型的过去、现在与未来
  • 51单片机驱动 矩阵键盘
  • SPOJ 11576 TRIP2 - A Famous King’s Trip 【Tarjan+欧拉回路】
  • Python清空Word段落样式的方法
  • PINNs案例——多介质分区温度场
  • c++环境和vscode常用的一些有用插件
  • 菲索旋转齿轮法:首次地面光速测量的科学魔术
  • Spring Boot 集成 Elasticsearch 的详细步骤
  • Arduino按键开关编程详解
  • Ubuntu 安装 MySQL8
  • Mybatis学习笔记
  • pytest——参数化
  • btrace1.0使用方法
  • AE模板 300个故障干扰损坏字幕条标题动画视频转场预设
  • mysql--索引
  • VulnHub-DC-2靶机
  • 【数据结构】励志大厂版·初阶(复习+刷题):栈与队列
  • 【Unity 游戏开发】角色控制模块技术要点拆解
  • 详细介绍Python-pandas-DataFrame全部 *功能* 函数
  • 【人工智能】图神经网络(GNN)的推理方法
  • 模型之FIM(Fill-In-the-Middle)补全
  • ADG网络故障恢复演练
  • tiktok web X-Bogus X-Gnarly 分析
  • FreeRTOS任务管理与通信机制详解
  • IPD研学:76页页基于IPD思想-华为需求管理培训方案【附全文阅读】
  • 初学python的我开始Leetcode题8-3