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

【落羽的落羽 C++】vector

在这里插入图片描述

文章目录

  • 一、vector类介绍
  • 二、vector中的常用接口
  • 三、迭代器失效问题
  • 四、vector的使用实例
  • 五、vector模拟实现

一、vector类介绍

vector是STL中的一种容器,本质上是顺序表。它和string类的结构很相似,其也有size、capacity、数组等,不同的是string底层只是字符数组,而vector类的底层是可以存储所有数据类型的数组。有了string的经验,我们理解vector就更轻松了。

vector实际上是一个类模板,在使用时,我们需要根据实际要存储的数据类型用<>表明,如vector<int> v1; vector<char> v2; vector<string> v3;等等

tip:vector<char>string看起来似乎没什么区别,但是string会在字符串后自动加\0,而前者不会,同时string中也有一些针对字符串的特殊操作也是vector中没有的。实际中根据我们的需求来选择使用。

二、vector中的常用接口

vector的接口和string中几乎完全一样,使用方法也类似,就简单介绍一下:

vector成员接口说明
size获取数据个数
capacity获取空间容量大小
resize改变vector的size
reserve改变vector的capacity
begin获取第一个数据的迭代器iterator/const_iterator
end获取最后一个数据的下一个位置的迭代器iterator/const_iterator
push_back尾部插入数据
pop_back尾部删除数据
insert插入数据
erase删除数据
swap交换两个vector的数据空间
operator[]使能像数组一样访问vector存储的数据

简单演示:
在这里插入图片描述

三、迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际上就是一个指针,或者是对指针进行了封装,比如vector<T>的迭代器就是原生态指针T*。因此迭代器失效就是迭代器底层对应指针所指向的空间被销毁了,类似野指针的道理,使用可能会造成程序崩溃。对于vector,可能会导致其迭代器失效的操作有:resize、reserve、insert、assign、push_back,这些操作可能会进行扩容操作,vector底层旧空间被释放而开辟了一块新空间,则指向旧空间的迭代器就失效了。因此,在以上操作完成之后,如果还想要通过迭代器操作vector中的元素,需要给迭代器重新赋值。举个例子:

#include<iostream>
#include<vector>
using namespace std;
int main()
{vector<int> v = { 1, 2, 3, 4, 5 };vector<int>::iterator it = v.begin();//将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容v.resize(10, 0);//此时原来的迭代器it失效,使用程序会崩溃cout << *it;return 0;
}

在这里插入图片描述

#include<iostream>
#include<vector>
using namespace std;
int main()
{vector<int> v = { 1, 2, 3, 4, 5 };vector<int>::iterator it = v.begin();//将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容v.resize(10, 0);//此时原来的迭代器it失效,使用程序会崩溃//cout << *it;//给it重新赋值就能解决it = v.begin();while(it != v.end()){cout << *it << ' ';it++;}cout << endl;return 0;
}

在这里插入图片描述
除此之外,erase操作也会导致迭代器失效,erase删除pos位置数据后,pos位置之后的元素会往前挪动,没有造成底层空间的改变,理论上迭代器不会失效。但是如果pos位置刚好是最后一个数据,删完之后pos刚好是end的位置,而end位置是没有数据的,那么pos就失效了。因此在VS下,只要使用erase操作后,VS就认为该位置迭代器失效了。解决办法也是一样,重新赋值。

VS对迭代器失效的检查比较严格,程序会直接崩溃。而Linux下g++编译器对迭代器失效的检测较为宽松,程序可能可以运行,但是结果也会出错。

在这里插入图片描述

四、vector的使用实例

力扣题目:杨辉三角
杨辉三角想必大家都不陌生,如果想要生成杨慧三角的前numRows行,用vector来实现就很方便了,我们可以定义出vector<vector<int>>的结构,表示它存储的数据类型是vector<int>,模拟出杨辉三角的结构:
在这里插入图片描述

vector<vector<int>> generate(int numRows) 
{vector<vector<int>> vv;vv.resize(numRows);//将每一个元素都初始化成1for(int i = 0; i < vv.size(); i++){vv[i].resize(i+1, 1);}//遍历赋值for(int i = 2; i < numRows; i++){for(int j = 1; j < i; j++){vv[i][j] = vv[i-1][j] + vv[i-1][j-1];}}return vv;
}

结果没有问题
在这里插入图片描述

五、vector模拟实现

在我的vector.h中:

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lydly
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}//利用迭代器区间构造template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}//使我们可以用{}初始化vector(initializer_list<T> il){reserve(il.size());for (auto& e : il){push_back(e);}}vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}//利用std库中的swap算法void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}size_t capacity() const{return _end_of_storage - _start;}size_t size() const{return _finish - _start;}T& operator[](size_t i){assert(i < size());return _start[i];}void resize(size_t n, T val = T()){if (n > size()){reserve(n);}while (_finish != _start + n){*_finish = val;_finish++;}}void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];if (_start){//深拷贝for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}}void push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;}void pop_back(){assert(_finish > _start);_finish--;}iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity * 2;reserve(newcapacity);pos = _start + pos;}//pos后的数据往后挪一个位置iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;it--;}*pos = x;_finish++;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);//pos后的数据往前挪一个位置iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;it++;}_finish--;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}

简单测试:
在这里插入图片描述
在这里插入图片描述

本篇完,感谢阅读。

相关文章:

  • 水果成篮--LeetCode
  • leetcode201.数字范围按位与
  • 双极坐标系的面积元
  • RabbitMQ 四种交换机(Direct、Topic、Fanout、Headers)详解
  • 端到端自动驾驶的数据规模化定律
  • 【Vue】Vue3项目创建
  • Dify框架面试内容整理-Dify框架
  • WPF高级用法示例
  • 服务器传输数据存储数据建议 传输慢的原因
  • 使用MyBatis注解方式的完整示例,涵盖CRUD、动态SQL、分页、事务管理等场景,并附详细注释和对比表格
  • linux的例行性工作(at)
  • JS自动化获取网站信息开发说明
  • 巧用 Element - UI 实现图片上传按钮的智能隐藏
  • 【linux】SSH 连接 WSL2 本地环境的完整步骤
  • 《探秘计算机启动幕后英雄:BIOS/UEFI与GRUB/bootloader》
  • 苹果计划2026年底前实现美版iPhone“印度造”,以减轻关税及地缘政治风险
  • 【Linux网络】HTTP协议全解析 - 从请求响应到方法与Header
  • 【NeurlPS 2024】MAR:无矢量量化的自回归图像生成
  • 5G融合消息PaaS项目深度解析 - Java架构师面试实战
  • Adruino:人机界面及接口技术
  • 证据公布!菲律宾6人非法登上铁线礁活动
  • 最高法专门规范涉企案件审执工作:从源头防止趋利性执法司法
  • 我国首次实现地月距离尺度的卫星激光测距
  • 《我的后半生》:人生下半场,也有活力重启的可能
  • 国家市场监管总局:民生无小事,严打民生领域侵权假冒违法行为
  • 青海一只人工繁育秃鹫雏鸟破壳后脱险成活,有望填补国内空白