[C++笔记]vector
vector
vector的说明文档
- vector是表示可变大小数组的序列容器(动态顺序表)。
- 就像数组一样,vector也采用连续的存储空间来储存元素。这就意味着可以用下标对vector的元素进行访问,和数组一样高效。与数组不同的是,它的大小可以动态改变——由容器自动处理。
- 底层而言,vector使用动态分配的数组来存储元素。当新元素插入时,这个数组可能需要被重新分配大小(扩容)。其做法为,分配一个新的数组,然后将所有元素移到这个新数组。就时间成本而言,这是一个代价较高的行为,因此不会在每次向容器添加元素时都重新分配大小。
- vector会分配一些额外的空间以应对可能需要的扩容,因此容器的实际容量大小可能大于容纳其元素所必须的存储空间的大小。不同的库采用不同的策略来权衡空间的使用(usage)与重新分配(reallocation)。但在任何情况下,重新分配都应该只发生在对数增长的大小间隔上,以使得尾插一个元素的时间复杂度为常数。
- 因此,相较于数组,vector占用了更多的存储空间以获得管理存储空间的能力,并以一种高效率的方式动态增长。
- 与其它动态序列容器相比(deque(双端队列),lists(双链表),forward_lists(单链表)), vector在访问其元素时非常高效(就像数组一样),而且从其末端添加或删除元素时也相对高效。对于在末端以外的位置插入或删除元素的操作,它的效率较低。而且与list和forward_lists相比,它的迭代器与引用不太一致。
string是负责管理字符类型的数组,而vector是负责管理任意类型的数组 。
string相比vector有太多冗余的接口,vector的设计相对更合理些。
vector构造函数
| vector构造函数 | 接口说明 |
|---|---|
| vector()(重点) | 无参构造 |
| vector (const vector& x); (重点) | 拷贝构造 |
| vector(size_type n, const value_type& val = value_type()) | 构造并初始化n个val |
| vector (InputIterator first, InputIterator last); | 使用迭代器进行初始化构造 |
vector容量管理
| 接口 | 接口说明 |
|---|---|
| resize(重点) | 改变vector的size |
| reserve (重点) | 改变vector的capacity |
| size | 获取数据个数 |
| capacity | 获取容量大小 |
| empty | 判断是否为空 |
- capacity的代码在vs和g++下分别运行可以发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。vector每次增容增多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
- reserve只负责开辟空间。如果明确知道需要用多少空间,可使用reserve来缓解vector增容代价较高的问题。
- resize在开空间的同时还会进行初始化,影响size。
vector增删查改
| 接口 | 接口说明 |
|---|---|
| push_back | (重点) 尾插 |
| pop_back | (重点) 尾删 |
| operator[] | (重点) 像数组一样访问 |
| find | 查找。(注意这个是算法模块实现,不是vector的成员接口) |
| insert | 在position之前插入val |
| erase | 删除position位置的数据 |
| swap | 交换两个vector的数据空间 |
vector迭代器
| 接口 | 接口说明 |
|---|---|
| begin +end(重点) | 获取第一个元素位置的iterator/const_iterator, 获取最后一个元素的下一位的iterator/const_iterator |
| rbegin + rend | 获取最后一个元素位置的reverse_iterator,获取第一个元素前一位的reverse_iterator |

vector 迭代器失效问题(重点)
- 迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际上就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。
- 而迭代器失效,实际上就是迭代器底层所对应的指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果便是程序崩溃(即,若继续使用已经失效的迭代器,程序可能会崩溃)。
===
对于vector,可能会导致其迭代器失效的操作有:
1.会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。
2.指定位置元素的删除操作–erase
3.注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
-SGI STL中,迭代器失效后,代码不一定会崩溃,但运行结果肯定不
对。若it不在begin和end范围内,肯定会崩溃。
4.与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
迭代器失效解决办法:在使用前,对迭代器重新赋值即可。
模拟实现vector
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <assert.h>
using namespace std;namespace my_vector {template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;vector(){}vector(size_t n, const T& val = T()) /*由于要兼容所有类型,缺省值不能为0,而是调默认构造函数构造匿名对象*/{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);}}//复用实现深拷贝/*vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}*///原生方式实现深拷贝vector(const vector<T>& v){_start = new T[v.capacity()];//memcpy(_start, v._start, sizeof(T) * v.size());//memcpy是浅拷贝,不适用于自定义类型for (size_t i = 0; i < v.size(); ++i){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();}template<class InputIterator>//允许类的成员函数本身是函数模板vector(InputIterator first, InputIterator last)/*迭代器区间 [first,last)*/{while (first != last) {//这里不能比较大小,有的结构,如链表,前后节点的地址大小关系并不确定push_back(*first);++first;}}~vector() {delete[] _start;_start = _finish = _end_of_storage = nullptr;}iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}void resize(size_t n, T val = T()) {//由于要兼容所有类型,缺省值不能为0,而是调默认构造函数构造匿名对象 if (n < size()) {_finish = _start + n;//等效于删除数据}else {if (n > capacity()) {reserve(n);while (_finish != _start + n) {*_finish = val;++_finish;}}}}void reserve(size_t n) {if (n > capacity()) {size_t sz = size();//提前记录sizeT* tmp = new T[n];if (_start) {//memcpy(tmp, _start, sizeof(T) * size());//memcpy是浅拷贝,不适用于自定义类型for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;//size()返回的是_finish - _start ,这里用size()的话会变成_finish=_start+_finish-_start ,_finish会变成0 ,只能用提前记录的sz_end_of_storage = _start + n;}}size_t capacity() const {return _end_of_storage - _start;}size_t size() const {return _finish - _start;}bool empty() {return _start == _finish;}T& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}void push_back(const T& x) {if (_finish == _end_of_storage) {//容量检查reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}void pop_back() {assert(!empty());//确保非空--_finish;}iterator insert(iterator pos, const T& val) {assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage) {//容量检查size_t len = pos - _start;//为防迭代器失效,需要在扩容前记录pos到_start的相对距离,以便在扩容后更新pos位置。reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;//扩容后用记录的相对距离更新pos位置,避免pos位置错误导致的迭代器失效(野指针型)}iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}iterator erase(iterator pos) {assert(pos >= _start);assert(pos < _finish);//pos不能等于_finishiterator start = pos + 1;while (start != _finish) {//挨个往前挪*(start - 1) = *start;++start;}--_finish;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};//===========类分隔线===========void func(const vector<int>& v) {cout << endl;for (size_t i = 0; i < v.size(); ++i) {cout << v[i] << " ";}cout << endl;vector<int>::const_iterator it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;cout << endl;}void test_vector1() {vector<int> v1;v1.push_back(0);v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);func(v1);for (size_t i = 0; i < v1.size(); ++i) {cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();vector<int>::iterator it = v1.begin();while (it != v1.end()) {cout << *it << " ";++it;}cout << endl;for (auto e : v1) {cout << e << " ";}cout << endl;}template<class T>void f() {T x = T();cout << x << endl;}void test_vector2() {//虽然内置类型理论上没有构造函数,但为兼容模板,一般支持像自定义类型一样用构造函数//int i = int();//会初始化为0//int j = int(1);//会初始化为1f<int>();f<int*>();f<double>();}void test_vector3() {vector<int> v1;v1.push_back(0);v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.size() << endl;cout << v1.capacity() << endl;v1.resize(10);cout << v1.size() << endl;cout << v1.capacity() << endl;func(v1);v1.resize(3);func(v1);}void test_vector4() {vector<int> v1;v1.push_back(0);v1.push_back(1);v1.push_back(2);v1.push_back(3);//v1.push_back(4);//*v1.insert(v1.begin(), 9);auto pos = find(v1.begin(), v1.end(), 2);if (pos != v1.end()) {//pos = v1.insert(pos, 50);v1.insert(pos, 50);}//insert后的pos默认看作已失效(野指针),不能再使用,因为位置关系变了for (auto e : v1) {cout << e << " ";}cout << endl;}void test_vector5() {vector<int> v1;v1.push_back(0);v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1) {cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);if (pos != v1.end()) {v1.erase(pos);}//类似于insert后,erase后pos也视作失效(野指针),因为位置关系也变了//(比如pos指向最后一个元素,erase这个元素后pos就指向了_finish,不再指向合法位置)//(*pos)++;//vs下会被检查到然后报错,linux下g++不检查但还是可能会出问题(行为结果未定义,与具体编译器实现有关)//string也会有迭代器失效的情况,但string的erase和insert更常用下标而不是迭代器,故问题不算明显。for (auto e : v1) {cout << e << " ";}cout << endl;}void test_vector6() {vector<int> v1;v1.push_back(0);v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1) {cout << e << " ";}cout << endl;//删除所有偶数:迭代器适合删除vector<int>::iterator it = v1.begin();while (it!=v1.end()){if (*it % 2 == 0) {it = v1.erase(it);//迭代器erase后失效,接收返回值以更新pos}else {++it;//迭代器未失效,正常++}}for (auto e : v1) {cout << e << " ";}cout << endl;}void test_vector7() {//vector<int> v1(10u, 5);//u表示无符号vector<int> v1(10, 5);for (auto e : v1) {cout << e << " ";}cout << endl;vector<int> v2(v1.begin() + 1, v1.end() - 1);for (auto e : v2){cout << e << " ";}cout << endl;std::string s1("hell word");vector<int> v3(s1.begin(), s1.end());for (auto e : v3){cout << e << " ";}cout << endl;int arr[] = {1,2,60,3,4,5};vector<int> v4(arr, arr + 4);for (auto e : v4){cout << e << " ";}cout << endl;v1.insert(v1.begin(), 8);for (auto e : v1){cout << e << " ";}cout << endl;sort(v1.begin(), v1.end());for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : arr){cout << e << " ";}cout << endl;sort(arr, arr + sizeof(arr) / sizeof(int), greater<int>());//sort默认升序。除了能对迭代器的区间排序,还可以对数组排序。for (auto e : arr){cout << e << " ";}cout << endl;}void test_vector8(){vector<int> v1(10, 5);for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2(v1);for (auto e : v2){cout << e << " ";}cout << endl;vector<std::string> v3(3, "123456789123456789");for (auto e : v3){cout << e << " ";}cout << endl;vector<std::string> v4(v3);for (auto e : v4){cout << e << " ";}cout << endl;v4.push_back("1111111111");v4.push_back("2222222222");v4.push_back("3333333333");for (auto e : v4){cout << e << " ";}cout << endl;}}相关文章:
[C++笔记]vector
vector vector的说明文档 vector是表示可变大小数组的序列容器(动态顺序表)。就像数组一样,vector也采用连续的存储空间来储存元素。这就意味着可以用下标对vector的元素进行访问,和数组一样高效。与数组不同的是,它的大小可以动态改变——…...
Python 迁移学习实用指南:1~5
原文:Hands-On Transfer Learning with Python 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只关心如…...
【CSS重点知识】属性计算的过程
✍️ 作者简介: 前端新手学习中。 💂 作者主页: 作者主页查看更多前端教学 🎓 专栏分享:css重难点教学 Node.js教学 从头开始学习 ajax学习 标题什么是计算机属性确定声明值层叠冲突继承使用默认值总结什么是计算机属性 CSS属性值的计算…...
Java避免死锁的几个常见方法(有测试代码和分析过程)
目录 Java避免死锁的几个常见方法 死锁产生的条件 上死锁代码 然后 :jstack 14320 >> jstack.text Java避免死锁的几个常见方法 Java避免死锁的几个常见方法 避免一个线程同时获取多个锁。避免一个线程在锁内同时占用多个资源,尽量保证每个锁…...
go binary包
binary包使用与详解 最近在看一个第三方包的库源码,bigcache,发现其中用到了binary 里面的函数,所以准备研究一下。 可以看到binary 包位于encoding/binary,也就是表示这个包的作用是编辑码作用的,看到文档给出的解释…...
CompletableFuture使用详解(IT枫斗者)
CompletableFuture使用详解 简介 概述 CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时CompletableFuture实现了对任务编排的能力。借助这项能力…...
4.15--设计模式之创建型之责任链模式(总复习版本)---脚踏实地,一步一个脚印
一、什么是责任链模式: 责任链模式属于行为型模式,是为请求创建了一个接收者对象的链,将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。 当一个请求从链式的首端发出时&a…...
STM32+W5500实现以太网通信
STM32系列32位微控制器基于Arm Cortex-M处理器,旨在为MCU用户提供新的开发自由度。它包括一系列产品,集高性能、实时功能、数字信号处理、低功耗/低电压操作、连接性等特性于一身,同时还保持了集成度高和易于开发的特点。本例采用STM32作为MC…...
全网最详细,Jmeter性能测试-性能基础详解,终成测试卷王(一)
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 发起请求 发起HTTP…...
人工智能概述
一、人工智能发展必备三要素 算法 数据 算力 CPU、GPU、TPU 计算力之CPU、GPU对比: CPU主要适合I\O密集型任务GPU主要适合计算密集型任务 什么样的程序适合在GPU上运行? 计算密集型的程序 所谓计算密集型(Compute-intensive)的程序,就是…...
API接口安全—webservice、Swagger、WEBpack
API接口安全—webservice、Swagger、WEBpack1. API接口介绍1.1. 常用的API接口类1.1.1. API接口分类1.1.1.1. 类库型API1.1.1.2. 操作系统型API1.1.1.3. 远程应用型API1.1.1.4. WEB应用型API1.1.1.5. 总结1.1.2. API接口类型1.1.2.1. HTTP类接口1.1.2.2. RPC类接口1.1.2.3. web…...
从前M个字母中取N个的无重复排列 [2*+]
目录 从前M个字母中取N个的无重复排列 [2*+] 程序设计 程序分析 从前M个字母中取N个的无重复排列 [2*+] 输出从前M个字母中取N个的无重复字母排列 Input 输入M N 1<=M=10, N<=M Output 按字典序输出排列 Sample Input 4 2 Sample Output A B A C A D B A B C B …...
ES forceMerge 强制段合并为什么会提升检索性能?
根据以前的测试,forceMerge段合并,将段的个数合并成一个。带来了将近一倍的性能提升,测试过程文档(请参考我的另外一篇文章):ES优化实战- forceMerge搜索提升测试报告_es forcemerge_水的精神的博客-CSDN博…...
macOS Ventura 13.3.1 (22E261) Boot ISO 原版可引导镜像
本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 macOS Ventura 13.3.1 为 Mac 提供下…...
html+css+JavaScript+json+servlet的社区系统(手把手教学)
目录 课前导读: 一、系统前期准备 二、前端代码的编写 三、登陆页面简介 四、注册页面 五、社区列表页 六、社区详情页 七、社区发帖页 八、注销 九、访问链接 登陆页面http://175.178.20.77:8080/java106_blog_system/login.html 总结: 课前…...
UI Toolkit(1)
UI ToolkitUI Toolkit界面画布设置背景制作UI布局UI Toolkit界面 在Unity 2021LTS版本之后UI Toolkit也被内置在Unity中,Unity有意的想让UI Toolkit 成为UI的主要搭建方式,当然与UGUI相比还是有一定的差别。他们各有有点,这次我们就开始介绍…...
vLive带你走进虚拟直播世界
虚拟直播是什么? 虚拟直播是基于5G实时渲染技术,在绿幕环境下拍摄画面,通过实时抠像、渲染与合成,再推流到直播平台的一种直播技术。尽管这种技术早已被影视工业所采用,但在全民化进程中却是困难重重,面临…...
初谈 ChatGPT
引子 最近,小编发现互联网中的大 V 突然都在用 ChatGPT 做宣传:“ChatGPT不会淘汰你,能驾驭ChatGPT的人会淘汰你”、“带领一小部分人先驾驭ChatGPT”。 确实,ChatGPT这个新生事物,如今被视为蒸汽机、电脑、iPhone 般的…...
JAVA练习103-螺旋矩阵
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 提示:这里可以添加本文要记录的大概内容: 4月9日练习内容 提示:以下是本篇文章正文内容,下面案例可供参考 一、题目-螺…...
RecvByteBufAllocator内存分配计算
虽然了解了整个内存池管理的细节,包括它的内存分配的具体逻辑,但是每次从NioSocketChannel中读取数据时,应该分配多少内存去读呢? 例如,客户端发送的数据为1KB , 应该分配多少内存去读呢? 例如:…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
