[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 , 应该分配多少内存去读呢? 例如:…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...