Vector

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析2

在这里插入图片描述


目录

  • 👉🏻vector概念
  • 👉🏻vector constructor
  • 👉🏻vector 容量
  • 👉🏻vector 增删查改
  • 🌅vector的模拟实现
    • 构造函数和析构函数
    • 拷贝构造、赋值、swap
    • size和capacity
    • reserve
    • resize
    • push_back
    • 迭代器和访问
    • insert
    • erase
    • 模板构造函数(迭代器区间)
    • 构造函数(初始化n个val值)
  • 🌩迭代器失效问题
    • insert和erase导致的迭代器失效
  • 👉🏻电话号码的字母组合

👉🏻vector概念

作为C++STL中的一个类模板,vector是一个动态数组容器,可以存储任意类型的元素。它提供了许多方便的方法来操作和管理数组。

以下是vector的一些特点和用法:

  1. 动态大小:vector可以根据需要自动调整大小,无需手动指定数组的大小。
  2. 随机访问:可以通过索引来访问和修改vector中的元素,例如myVector[0]。
  3. 插入和删除:可以在任意位置插入和删除元素,例如myVector.insert(position, value)和myVector.erase(position)。
  4. 动态增长:当vector的容量不足时,会自动分配更多的内存空间,以容纳更多的元素。
  5. 迭代器支持:可以使用迭代器来遍历vector中的元素,例如使用for循环或std::for_each函数。
  6. 元素访问:可以使用at()方法或[]运算符来访问元素,例如myVector.at(index)或myVector[index]。
  7. 大小和容量:可以使用size()方法获取vector中元素的数量,使用capacity()方法获取vector的容量。

vector官方文档

👉🏻vector constructor

在这里插入图片描述

  • vector()(重点) 无参构造
  • vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
  • vector (const vector& x); (重点) 拷贝构造
  • vector (InputIterator first, InputIterator last); 使用迭代器进行初始化构造

👉🏻vector 容量

  • size 获取数据个数
  • capacity 获取容量大小
  • empty 判断是否为空
  • resize(重点) 改变vector的size
  • reserve (重点) 改变vector的capacity

capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。
这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义
的。vs是PJ版本STL,g++是SGI版本STL。
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问

👉🏻vector 增删查改

  • push_back(重点) 尾插

  • pop_back (重点) 尾删

  • find 查找。(注意这个是算法模块实现,不是vector的成员接口)
    在这里插入图片描述

  • insert 在position之前插入val
    在这里插入图片描述

  • erase 删除position位置的数据

  • swap 交换两个vector的数据空间
    在这里插入图片描述

  • operator[] (重点) 像数组一样访问

🌅vector的模拟实现

构造函数和析构函数

 vector():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}
~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}

拷贝构造、赋值、swap

 vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserve(v.capacity());//先开一个和v一样大的空间//而后直接将v中的数据插入到_start中for (auto x : v){push_back(x);}}
 //写完拷贝构造后,我们就可以开始写赋值了vector<T>& operator=(vector<T> tmp){swap(tmp);return *this;}void  swap(vector<T>& v)//打工人swap{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}

size和capacity

size_t size(){return _finish - _start;}
size_t capacity(){return _endofstorage - _start;}

reserve

void reserve(size_t n){if (n > capacity())//不缩容{T* tmp = new T[n];size_t sz = size();//记录一下_finish和_start的偏移量✨if (_start != nullptr){memcpy(tmp, _start, sizeof(T) * sz);delete[] _start;//释放旧空间}_start = tmp;_finish = tmp + sz;_endofstorage = _start + n;}}

这里memcpy()有个大坑,如果针对整型等浅拷贝的拷贝是没问题的。
但是如果拷贝的类型是string呢?
我们这里举个例子:

	void test_vector3(){vector<string> v;for (int i = 0; i < 5; i++){v.push_back("11111111111111111111");}for (auto str : v){cout << str << " ";}}

在这里插入图片描述
那么这里错在哪呢?
在这里插入图片描述
所以为了避免浅拷贝,我们还是只能自己动手,丰衣足食了,就不借助memcpy了。
这里我们直接用string的赋值运算符,可以直接拷贝构造无需担心浅拷贝问题。

void reserve(size_t n){if (n > capacity())//不缩容{T* tmp = new T[n];size_t sz = size();if (_start != nullptr){for (int i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;//释放旧空间}_start = tmp;_finish = tmp + sz;_endofstorage = _start + n;}}

这样就解决问题了😄

resize

void resize(size_t n, const T& val = T())//因为T()是匿名对象是临时变量具有常性,所以引用传参不能权限放大得加const{if (n <= size()){_finish = _start + n;}else{reserve(n);//先开辟n大的空间//然后再进行插入数据while (_finish < _start + n){*_finish = val;_finish++;}}}

push_back

void push_back(const T& x){if (_endofstorage == _finish){size_t cp = capacity() == 0 ? 4 : capacity() * 2;reserve(cp);//T* tmp = new T[cp];//if (_start != nullptr)//{//	memcpy(tmp, _start, sizeof(T) * size());//		delete[] _start;//释放旧空间//}//_finish = tmp + size();//_finish = tmp + size()一定要先写,那不然_start先修改,size()大小会不理想//_start = tmp;_endofstorage = _start + cp;}*_finish = x;_finish++;}

迭代器和访问

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;}
T& operator[](size_t pos){assert(pos < size());return _start[pos];}T& operator[](size_t pos)const //写个常量访问{assert(pos < size());return _start[pos];}

insert

void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage)//扩容情况{//迭代器失效问题:扩容后_start指向新空间,但是Pos仍然指向旧空间//我们先记录原来_start和Pos的偏移量//扩容后,pos再指向新空间中新位置size_t offset = pos - _start;//记录偏移量reserve(capacity() == 0 ? 0 : capacity() * 2);pos = _start + offset;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;//数据挪动end--;}*(pos) = x;++_finish;}

erase

会导致迭代器失效版本

void erase(iterator  pos){assert(pos >= _start);assert(pos <= _finish);iterator end = _finish - 1;while (pos < end){*pos = *(pos + 1);pos++;}_finish--;}

模板构造函数(迭代器区间)

vector的构造函数中,还提供了模板构造函数。
在这里插入图片描述

 template <class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){while (first != last){push_back(*first);++first;}}

有人会问,既然是用迭代器区间初始化,为什么不能用vector自己本身的iterator呢?
可以是可以,但格局就小啦。
在这里插入图片描述
如果我是用vector自己本身的iterator区间,那么假如说我这个vector的iterator是int*,那初始化也就是整型。
那如果我想初始化为字符串呢?
所以这里模板构造函数就显示出它的神通广大了,只要是迭代器区间,我都可以接收,这不香吗?😍

⭐️补充小知识点

当我们写了拷贝构造函数、模板构造函数、或者其它重载构造函数时
总之只要写了,默认无参构造函数一定要写出来(即使你并没有做什么)
默认无参构造函数是最基本的,如果不写,编译器就会使用它自己的默认构造函数。而这时,你写的其它构造函数都不会生效了

构造函数(初始化n个val值)

 vector(size_t n, const T val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(int n, const T val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}

为什么这里还要多此一举再写个重载?
因为我们上面的模板函数缘故,为了使(int,int)的传参更好的匹配到构造函数(初始化n个val值),我们写了一个参数类型为int 的n

🌩迭代器失效问题

C++中的迭代器失效是指在对容器进行修改操作后,之前获取的迭代器可能会变得无效。这意味着在迭代器失效后,尝试使用该迭代器进行访问或操作容器的行为将导致未定义的行为。

迭代器失效的常见情况包括:

  • 在向容器中插入删除元素后,指向被修改位置的迭代器会失效。
  • 在对容器进行重分配内存的操作后,所有指向容器元素的迭代器都会失效。
  • 在使用迭代器遍历容器时,如果在遍历过程中对容器进行了修改操作,迭代器也会失效。

为了避免迭代器失效,可以采取以下措施:

  • 在进行插入或删除操作后,更新迭代器,使其指向有效的位置。
  • 在遍历容器时,避免在循环内部对容器进行修改操作。
  • 在进行可能导致迭代器失效的操作之前,先将迭代器保存下来,以便需要时重新定位

insert和erase导致的迭代器失效

在上述的vector模拟实现中,我们实现了insert和erase的功能。
但是它们会导致怎样的迭代器失效问题呢?
insert

	void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage)//扩容情况{//迭代器失效问题:扩容后_start指向新空间,但是Pos仍然指向旧空间//我们先记录原来_start和Pos的偏移量//扩容后,pos再指向新空间中新位置size_t offset = pos - _start;//记录偏移量reserve(capacity() == 0 ? 0 : capacity() * 2);pos = _start + offset;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;//数据挪动end--;}*(pos) = x;++_finish;}

上述代码是经过优化改正的,这个是已经解决迭代器问题了。
但我们还得分析一下问题所在
为什么要记录pos和_start偏移量?
因为我们在扩容时,会开辟新空间,当_start指向新空间时,此时pos还是指向旧空间。
所以为了使pos指向正确的位置,我们得先记录它和_start的偏移量,而后新的_start加上偏移量就是pos在新空间的位置。

erase
会导致迭代器失效版本

void erase(iterator  pos){assert(pos >= _start);assert(pos <= _finish);iterator end = _finish - 1;while (pos < end){*pos = *(pos + 1);pos++;}_finish--;}

我们举个删除偶数的例子。

void test_vector2(){vector<int> v;for (int i = 1; i <= 6; i++){v.push_back(i);}vector<int>::iterator it = v.begin();while (it != v.end()){if (*it % 2 == 0){v.erase(it);}it++;}for (auto x : v){cout << x << " ";}}

在这里插入图片描述
我们发现这里崩溃出错了,而且问题是pos>_finish引起的。
我们看看具体过程
在这里插入图片描述
上述过程中的主要问题就是it进行++后指向出现的问题。
那么怎么解决这个问题呢?
实际上c++官方就已经注意到了这个问题,所以,它所设置的erase,会返回函数调用擦除的元素后面元素的新位置的迭代器。
在这里插入图片描述
所以,在模拟实现这里我们也要这么做。

iterator erase(iterator  pos){assert(pos >= _start);assert(pos <= _finish);iterator end = _finish - 1;iterator p = pos;while (p < end){*p = *(p + 1);p++;}_finish--;return pos;//返回被删的位置}

所以可以有

while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);}elseit++;//不是偶数再++}

总结
上述中,我们解决迭代器失效问题的主要思路就是在进行插入或删除操作后,更新迭代器,使其指向有效的位置
而迭代器所谓失效,就是看看在具体情况中,它所指向的元素位置是否和我们预想的有所偏差,如果有偏差,则就会导致迭代器失效

👉🏻电话号码的字母组合

原题链接:电话号码的字母组合

class Solution {
public:const char* numsArr[10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};void Combine(const string& digits,string combinestr,int i ,vector<string>& ret){if(i == digits.size())//当数字中的字母全部都进行完组合后{ret.push_back(combinestr);return;}int num = digits[i] - '0';string str = numsArr[num];for(auto ch:str)//将当前数字代表的全部字母拿去依次拿去跟其它数字的字母进行组合{Combine(digits,combinestr+ch,i+1,ret);}}vector<string> letterCombinations(const string& digits) {vector<string> v;//存储全部组合的字符串if(digits=="")return v;string str;//这个是专门用来组合的字符串int i =0;Combine(digits,str,i,v);return v;}
};

如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/41157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

selenium 选定ul-li下拉选项中某个指定选项

场景&#xff1a;selenium的下拉选项是ul-li模式&#xff0c;选定某个指定的选项。 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 显示等待def select_li(self, text, *ul_locator):"…

python+django+mysql高校校园外卖点餐系统--计算机毕设项目

本文的研究目标是以高校校园外卖点餐为对象&#xff0c;使其高校校园外卖点餐为目标&#xff0c;使得高校校园外卖点餐的信息化体系发展水平提高。论文的研究内容包括对个人中心、美食分类管理、用户管理、商家管理、美食信息管理、工作人员管理、安全检查管理、系统管理、订单…

时序预测 | MATLAB实现基于GRU门控循环单元的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于GRU门控循环单元的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于GRU门控循环单元的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 1.Matlab实现GRU门控循环单元时间序列预测未…

复数混频器、零中频架构和高级算法开发

文章里讲解了关于射频IQ调制器、零中频架构相关的原理及技术&#xff0c;全都是干货&#xff01;其实好多同行对软件无线电的原理、IQ调制、镜像抑制都是一知半解&#xff0c;知其然不知其所以然。好好研读这篇文章&#xff0c;相信会让你有种恍然大悟的感觉。 RF工程常被视为…

Shell学习笔记之基础部分

Shell基础&#xff1a; 查看操作系统支持的shell&#xff1a; [rootrhel9 ansible]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bashShell的基本元素&#xff1a; 声明&#xff1a;声明用哪个命令解释器来解释并执行当前脚本文件中的语句&#xff0c;一般写的…

大语言模型与语义搜索;钉钉个人版启动内测,提供多项AI服务

&#x1f989; AI新闻 &#x1f680; 钉钉个人版启动内测&#xff0c;提供多项AI服务 摘要&#xff1a;钉钉个人版正式开始内测&#xff0c;面向小团队、个人用户、高校大学生等人群。该版本具有AI为核心的功能&#xff0c;包括文生文AI、文生图AI和角色化对话等。用户可通过…

【IEEE会议】第二届IEEE云计算、大数据应用与软件工程国际学术会议 (CBASE2023)

第二届IEEE云计算、大数据应用与软件工程国际学术会议 (CBASE2023&#xff09; 随着大数据时代的到来&#xff0c;对数据获取的随时性和对计算的需求也在逐渐增长。为推动大数据时代的云计算与软件工程的发展&#xff0c;促进该领域学术交流&#xff0c;在CBASE 2022成功举办的…

基于docker搭建pytest自动化测试环境(docker+pytest+jenkins+allure)

pytest搭建自动化测试环境&#xff08;dockerpytestjenkinsallure&#xff09; 这里我以ubuntu18为例 如果有docker环境&#xff0c;可以直接拉取我打包好的镜像docker pull ziyigun/jenkins:v1.0 1 搭建Docker 1.1 安装docker # 配置docker安装环境 sudo apt-get install ap…

润和软件HopeStage操作系统正式上架阿里云、华为云、腾讯云商店

近日&#xff0c;润和软件HopeStage操作系统正式上架阿里云、华为云、腾讯云商店。 随着科技的发展&#xff0c;云服务成为现代社会信息和资讯的交换、共享、存储、检索、应用等重要方式。阿里云、华为云、腾讯云作为我国云服务市场三巨头&#xff0c;其云商店产品全面覆盖云、…

Nvidia Jetson 编解码开发(1)介绍

前言 由于项目需要,需要开发Jetson平台的硬件编解码; 优化CPU带宽,后续主要以介绍硬件编解码为主 1.Jetson各平台编解码性能说明 如下是拿了Jetson nano/tx2/Xavier等几个平台做对比; 这里说明的编解码性能主要是对硬件来说的 2. 编解码实现说明 2.1 软件编解码 优点:…

Idea中隐藏指定文件或指定类型文件

Setting ->Editor ->Code Style->File Types → Ignored Files and Folders输入要隐藏的文件名&#xff0c;支持*号通配符回车确认添加

Windows权限维持—自启动映像劫持粘滞键辅助屏保后门WinLogon

Windows权限维持—自启动&映像劫持&粘滞键&辅助屏保后门&WinLogon 1. 前置2. 自启动2.1. 路径加载2.1.1. 放置文件2.1.2. 重启主机 2.2. 服务加载2.2.1. 创建服务2.2.2. 查看服务2.2.3. 重启主机 2.3. 注册表加载2.3.1. 添加启动项2.3.2. 查看注册表2.3.3. 重启…

YOLOv5基础知识入门(7)— NMS(非极大值抑制)原理解析

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。NMS是指非极大值抑制&#xff08;non maximum suppression&#xff09;&#xff0c;它是一种常用于物体检测任务的算法。在物体检测中&#xff0c;通常会有多个预测框&#xff08;bounding box&#xff09;被提议出来&…

机器学习深度学习——transformer(机器翻译的再实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——自注意力和位置编码&#xff08;数学推导代码实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器…

【论文阅读】 Model Sparsity Can Simplify Machine Unlearning

Model Sparsity Can Simplify Machine Unlearning 背景主要内容Contribution Ⅰ&#xff1a;对Machine Unlearning的一个全面的理解Contribution Ⅱ&#xff1a;说明model sparsity对Machine Unlearning的好处Pruning方法的选择sparse-aware的unlearning framework Experiments…

JetBrains IDE远程开发功能可供GitHub用户使用

JetBrains与GitHub去年已达成合作&#xff0c;提供GitHub Codespaces 与 JetBrains Gateway 之间的集成。 GitHub Codespaces允许用户创建安全、可配置、专属的云端开发环境&#xff0c;此集成意味着您可以通过JetBrains Gateway使用在 GitHub Codespaces 中运行喜欢的IDE进行…

VScode搭建Opencv(C++开发环境)

VScode配置Opencv 一、 软件版本二 、下载软件2.1 MinGw下载2.2 Cmake下载2.3 Opencv下载 三、编译3.1 cmake-gui3.2 make3.3 install 四、 VScode配置4.1 launch.json4.2 c_cpp_properties.json4.3 tasks.json 五、测试 一、 软件版本 cmake :cmake-3.27.2-windows-x86_64 Mi…

JAVA基础知识(一)——Java语言描述、变量和运算符

TOC(Java语言描述、变量和运算符) 一、JAVA语言描述 1.1 java语言描述 JDK、JRE、jVM三者之间的关系&#xff0c;以及JDK、JRE包含的主要结构有哪些&#xff1f; JDKJre java的开发工具&#xff08;javac.exe java.exe javadoc.exe&#xff09; jre jvmjava的核心类库 为什…

【JavaEE基础学习打卡03】Java EE 平台有哪些内容?

目录 前言一、Java EE平台说明二、Java EE平台容器及组件1.平台容器2.平台组件 三、JavaEE平台API服务1.API服务概览2.平台API 总结 前言 &#x1f4dc; 本系列教程适用于Java Web初学者、爱好者&#xff0c;小白白。我们的天赋并不高&#xff0c;可贵在努力&#xff0c;坚持不…

使用CLI添加磁盘到VM

登录 https://portal.azure.com/#home&#xff0c;点击右上角的控制台图标 &#xff0c;打开CLI 在控制台中输入如下指令&#xff0c;在NetworkWatcherRG创建一个名字为TEST的虚拟机&#xff0c;使用的镜像是Win2019datacenter&#xff0c;username是aaa,password是1234567890A…