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

【十二】【C++】vector用法的探究

vector类创建对象

 
/*vector类创建对象*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>class Date {public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;};//创建对象
void TestVector1() {vector<int> v1(10, 5);vector<int> v2(10);vector<Date> v3(10);vector<int> v4{ 1, 2, 3 };  // C++11vector<int> vec; // 创建一个空的int类型vectorvector<int> vec2(10); // 创建一个包含10个初始化为0的int元素的vectorvector<int> vec3(10, 1); // 创建一个包含10个初始化为1的int元素的vectorvector<int> vec4{1, 2, 3, 4, 5}; // 列表初始化vector<int> vec5(vec4.begin(), vec4.end()); // 范围初始化vector<int> vec6(vec4); // 拷贝初始化}
#endif

进入调试可以看到变量已经创建成功,里面的具体情况如下图所示。

vector类capacity的扩容规律

 
/*vector类capacity的扩容规律*/
#if 0
/*1. vs中:vector是按照1.5倍方式扩容  linux下是按照2倍方式扩容2. 放元素时如果已经知道大概要放多少个元素,可以提前将空间设置好避免:一边插入一边扩容效率低下*/
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>void TestVector2() {vector<int> v;v.reserve(10);
//    v.reserve(100);提前分配空间size_t cap = v.capacity();for (size_t i = 0; i < 100; ++i) {v.push_back(i);if (cap != v.capacity()) {cap = v.capacity();cout << cap << endl;}}}
int main(){TestVector2();}
#endif

这段代码演示了如何在C++中使用std::vector,特别关注其动态扩容的行为,并提供了一个实用的建议,即如果预先知道将要存储的元素数量,可以使用reserve方法来提前分配足够的空间,以避免在添加元素时频繁的动态扩容操作,从而提高效率。

代码解释

vector<int> v; 创建了一个名为v的空vector,用于存储int类型的元素。

v.reserve(10); 使用reserve方法为v预先分配足够的空间,以存储至少10个int类型的元素。这是基于先前的建议:如果已知将要存储的元素数量,预先分配空间可以提高效率。

size_t cap = v.capacity(); 初始化cap变量,用于存储v当前的容量。

接下来的循环中,通过push_back方法向v中添加了100个整数(从0到99)。每次添加元素后,都会检查v的容量是否发生变化:

如果容量发生变化(意味着vector进行了扩容),则更新cap变量,并输出新的容量值。

扩容机制

代码中的注释提到了std::vector扩容机制的平台相关性:

在Visual Studio(VS)环境下,std::vector通常按照1.5倍的方式扩容。

在Linux环境下,std::vector可能按照2倍的方式扩容。

这种差异意味着在不同的平台上,相同的代码可能会有不同的内存使用和性能表现。

vector访问元素的方式

 
/*vector访问元素的方式*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
void TestVector3() {vector<int> v{ 1, 2, 3, 4, 5 };cout << v.front() << endl;cout << v.back() << endl;v.front() = 10;v.back() = 50;cout << v[13] << endl;cout << v.at(14) << endl;v.clear();cout << v.front() << endl;cout << v.back() << endl;}
int main(){TestVector3();}
#endif

注释16、17、19行的代码,运行代码。

v.front()返回v对象第一个元素,v.back()返回v对象最后一个元素。

注释19行的代码,运行代码。

v[13]访问下标为13的元素,越界访问,但是不会检查范围。

v.at(14)访问下标为14的元素,越界访问,会报错,会检查范围,报错后,后面的代码不会再运行。

assign用法,用数组代替vector内容

 
/*已经存在的vector对象,用一个数组代替vector内容*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>void TestVector4() {vector<int> v(3, 5);int array[] = { 1, 2, 3, 4, 5 };
//     v = array;  编译失败v.clear();for (int i = 0; i <(int)(sizeof(array) / sizeof(array[0])); ++i){v[i] = array[i];   // 越界v.push_back(array[i]);}v.assign(array, array + sizeof(array) / sizeof(array[0]));v.assign(10, 5);
}
int main(){TestVector4();}
#endif

注释20,23,25行代码,运行代码。

调试代码运行到结尾,发现v对象中lengthcapacity没有变化,原因很简单,我们只是简单修改v对象对应位置的值,但是v对象还有lengthcapacity成员变量需要改变。

注释19,23,25行代码,运行代码。

注释17-21,25行代码,运行代码。

v.assign(array, array + sizeof(array) / sizeof(array[0]));array数组的0位置到结尾,代替v里面的内容。

注释17-21,23行代码,运行代码。

vec4.assign(5, 10); 将vector中的内容替换为5个10

vector的插入操作insert探究

 
/*vector插入操作insert探究*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
void TestVector5() {vector<int> v{ 1, 2, 3 };v.insert(v.begin(), 0);v.insert(v.end(), 4);// 0 1 2 3 4// 在1号元素的位置插入10个5v.insert(v.begin() + 1, 10, 5);// 要在data元素所在的位置插入array数组int data;cin >> data;int array[] = { 10, 20, 30 };
//    vector<int>::iterator pos = find(v.begin(), v.end(), data);auto pos = find(v.begin(), v.end(), data);if (pos != v.end()) {v.insert(pos, array, array + sizeof(array) / sizeof(array[0]));}}
int main() {TestVector5();}
#endif

小结论:

迭代器begin()指向第一个元素,end()指向最后一个元素后面一个位置。

插入操作传参表示位置,传的都是迭代器。

都是在迭代器位置前面插入数据。

vector的删除操作erase探究

 
/*vector的删除erase操作探究*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
void TestVector6() {vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };v.erase(v.begin());v.erase(v.begin(), v.begin() + 5);v.erase(v.begin(), v.end());    // clear()
}
int main(){TestVector6();}
#endif

小结论:

删除多个元素,区间是左开右闭。

vector的交换操作swap探究

 
/*swap交换操作探究*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
void TestVector7() {vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };vector<int> v2{ 12, 23, 34 };swap(v1, v2);v1.swap(v2);}
int main(){TestVector7();}
#endif

vector的访问操作探究

 
/*vector访问操作探究*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
void TestVector8() {vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };for (size_t i = 0; i < v1.size(); ++i) {cout << v1[i] << " ";}cout << endl;for (auto e : v1) {cout << e << " ";}cout << endl;auto it = v1.begin();while (it != v1.end()) {cout << *it << " ";++it;}cout << endl;sort(v1.begin(), v1.end());}
int main(){TestVector8();}
#endif

访问vector的三种方式:

  1. operator[]访问

  2. 范围for

  3. 迭代器

vector的迭代器失效探究

 
// 迭代器失效
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>void TestVector9() {vector<int> v{ 1, 2, 3, 4, 5 };// it指向的是v的当前的起始位置auto it = v.begin();// 扩容之后,可能会导致扩容// 开辟新空间  拷贝元素  释放旧空间v.push_back(6);// it指向v之前的空间已经被释放了,it指向的空间就是非法的// it的迭代器已经失效了// 解决迭代器失效的方法:it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;}
int main(){TestVector9();}
#endif

扩容操作,开辟新的空间,而老迭代器还指向旧的空间,此时迭代器指向的空间是已经被消灭的空间,解决这个问题就必须重新让迭代器指向新空间的位置。

vector删除操作后返回下一个元素的迭代器位置

 
/*vector删除操作后返回下一个位置的迭代器位置*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>void TestVector10() {vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };auto it = v.begin();while (it != v.end()) {if (*it & 1 || *it == 0)it = v.erase(it);else++it;}}
int main() {TestVector10();}#endif

用vector创建二维数组

 
/*用vector创建二维数组*/
#if 1
/*用vector创建二维数组:1. 矩阵a. 所有元素都相同b. 元素不同2. 每行元素个数不同---比如杨慧三角*/#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
// a. 所有元素都相同
void TestVector11() {//     5行10列  所有元素都是8//    1.依次尾插vector<vector<int>> v1;v1.resize(5);for (int i = 0; i < 5; ++i){for (int j = 0; j < 10; ++j){v1[i].push_back(8);}}
//    2.无参构造,resizevector<vector<int>> v2;v2.resize(5, vector<int>(10, 8));
//    3.vector构造函数嵌套vector<vector<int>> v3(5, vector<int>(10, 8));}
int main(){TestVector11();}
#endif

vector<vector<int>> v3(5, vector<int>(10, 8));创建对象v3,元素数据类型是vector<int>类型,元素个数有五个,对这五个元素进行初始化,全部初始化为vector<int>(10,8),匿名对象构造函数。

常用于创建矩阵

 
/*用vector创建二维数组---杨慧三角*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>
// 2. 每行元素个数不同---比如杨慧三角
void TestVector12() {int n;cin >> n;// vector(size_t n, const T& val = T())// vector<vector<int>> vv(n, vector<int>());vector<vector<int>> vv(n);for (size_t i = 0; i < vv.size(); ++i) {vv[i].resize(i + 1, 1);}/*0:11:1  12:1  2  13:1  3  3  14:1  4  6  4  1。。。*/for (size_t i = 2; i < vv.size(); ++i) {for (size_t j = 1; j < vv[i].size() - 1; ++j) {vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}
int main(){TestVector12();}

使用reserve、resize的探究

 
/*使用reserve、resize的小技巧*/
#if 1
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <crtdbg.h>void TestVector13() {vector<int> v2;v2.reserve(10);v2[0] = 1;vector<int> v3;v3.resize(10);v3[0] = 1;vector<int> v1;v1[0] = 1;}
int main() {TestVector13();return 0;}
#endif

capacity容量,已经开辟的空间大小,length使用的空间大小。如果通过无参的构造函数创建v1lengthcapacity都是0,此时访问元素并修改会报错,因为此时v1还没有开辟空间。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

相关文章:

【十二】【C++】vector用法的探究

vector类创建对象 /*vector类创建对象*/ #if 1 #define _CRT_SECURE_NO_WARNINGS#include <iostream> using namespace std; #include <vector> #include <algorithm> #include <crtdbg.h>class Date {public:Date(int year 1900, int month 1, int …...

Docker 基本介绍

Docker 基本介绍 镜像 Docker镜像就是一个只读的模板。 例如&#xff1a;一个镜像可以包含一个完整的ubuntu操作系统环境&#xff0c;里面仅安装了Apache或用户需要的其它应用 程序。 镜像可以用来创建Docker容器。Docker提供了一个很简单的机制来创建镜像或者更新现有的镜…...

CentOS 7 安装 install abiword

安装 1.下载noarch安装包 wget http://repo.iotti.biz/CentOS/7/noarch/lux-release-7-1.noarch.rpm 2.安装noarch rpm -Uvh lux-release-7-1.noarch.rpm 3.安装abiword yum -y install abiword...

开源的直播平台

​​​​​​直播平台系统界面介绍 开源一套直播平台 私信可获取源码...

ChatGPT 变懒最新解释!或和系统Prompt太长有关

大家好我是二狗。 ChatGPT变懒这件事又有了最新解释了。 这两天&#xff0c;推特用户Dylan Patel发文表示&#xff1a; 你想知道为什么 ChatGPT 和 6 个月前相比会如此糟糕吗&#xff1f; 那是因为ChatGPT系统Prompt是竟然包含1700 tokens&#xff0c;看看这个prompt里面有多…...

书生·浦语大模型第三课作业

基础作业&#xff1a; 复现课程知识库助手搭建过程 (截图) 进阶作业&#xff1a; 选择一个垂直领域&#xff0c;收集该领域的专业资料构建专业知识库&#xff0c;并搭建专业问答助手&#xff0c;并在 OpenXLab 上成功部署&#xff08;截图&#xff0c;并提供应用地址&#x…...

【Redis笔记】分布式锁及4种常见实现方法

线程锁 主要用来给方法、代码块加锁。当某个方法或代码使用锁&#xff0c;在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果&#xff0c;因为线程锁的实现在根本上是依靠线程之间共享内存实现的&#xff0c;比如Synchronized、Lock等。 进程锁 控制同…...

SpringMVC第一天

一、SpringMVC简介 1 SpringMVC概述 1.1 SpringMVC概述 SpringMVC是一种基于Java实现MVC模型的轻量级Web框架 优点 使用简单&#xff0c;开发便捷&#xff08;相比于Servlet&#xff09; 灵活性强 2 入门案例【重点】 问题导入 在Controller中如何定义访问路径&#xff…...

如何利用腾讯工蜂提升广告推广和用户运营效率

无代码开发&#xff1a;腾讯工蜂的连接优势 在广告推广和用户运营中&#xff0c;腾讯工蜂的无代码开发优势让广告系统和用户运营系统能够轻松地实现无需API开发的集成。这使得没有专业编程技能的工作人员也能通过腾讯工蜂的用户友好界面&#xff0c;实现系统的快速连接和集成&…...

【QT+QGIS跨平台编译】之三十二:【MiniZip+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、MiniZip介绍二、文件下载三、文件分析四、pro文件五、编译实践一、MiniZip介绍 MiniZip是一个轻量级的开源库,用于创建、读取和操作ZIP文件格式的压缩文件。它提供了一组简单而灵活的API,可以方便地在应用程序中进行ZIP文件的压缩和解压操作。 MiniZip的主要特…...

OLAP技术的发展及趋势简述

这里写自定义目录标题 历史发展基于电子表格的数据分析基于传统数据库的数据分析基于大数据的数据分析 当下的现状OLAP技术的分类MOLAPROLAPHOLAP 主流的OLAP引擎新技术的普及内存向量计算列式数据存储及交换增量查询多源融合计算下推物化视图 发展趋势智能化分析多源融合和自动…...

stupid_brain

前言&#xff1a; 本文用于记录本人AI新手期间犯的各种错误&#xff0c;时常更新。 正文开始&#xff1a; 读取数据的num_worker设置过少&#xff0c;以至于训练速度卡在读取数据上。训练集数据处理&#xff1a;数据增强有利于解决过拟合问题。模型&#xff1a;relu少写、batc…...

C# BackgroundWorker的使用

C# 中的 BackgroundWorker 类是 .NET Framework 提供的一个组件&#xff0c;用于在后台线程上异步执行长时间运行的操作&#xff0c;同时保持与用户界面&#xff08;UI&#xff09;的交互&#xff0c;如更新进度信息或处理取消请求。这使得可以轻松地在不冻结UI的情况下执行耗时…...

(简单有案例)前端实现主题切换、动态换肤的两种简单方式

目录 背景 &#xff08;强烈推荐&#xff09;实现方法1&#xff1a;CSS中原生变量“--”和var() 步骤1&#xff1a;定义css变量 步骤2&#xff1a;使用CSS变量 步骤3&#xff1a;切换主题 实现完整案例 实现方法2&#xff1a;link 动态引入 背景 我们需要做一个功能&#…...

wyh的迷宫

涉及知识点&#xff1a;求迷宫能否到达终点的&#xff0c;而不是求路径数的&#xff0c;用bfs时可以不用重置状态数组&#xff08;回溯&#xff09;。 题目描述 给你一个n*m的迷宫&#xff0c;这个迷宫中有以下几个标识&#xff1a; s代表起点 t代表终点 x代表障碍物 .代…...

AWS云用户创建

问题 需要给工友创建AWS云的用户&#xff0c;这里假设使用分配给自己AWS开发者IAM账号&#xff0c;给别人创建aws IAM账号。 登录系统 打开页面&#xff1a;https://xxx.signin.aws.amazon.com/console&#xff0c;使用分配的开发者账号登录。如下图&#xff1a; 创建用户…...

微信小程序(三十七)选项点击高亮效果

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.选择性渲染类 2.以数字为需渲染内容&#xff08;数量&#xff09; 源码&#xff1a; index.wxml <view class"Area"><!-- {{activeNumindex?Active:}}是选择性添加类名进行渲染 -->&l…...

通过Demo学WPF—数据绑定(二)

准备 今天学习的Demo是Data Binding中的Linq&#xff1a; 创建一个空白解决方案&#xff0c;然后添加现有项目&#xff0c;选择Linq&#xff0c;解决方案如下所示&#xff1a; 查看这个Demo的效果&#xff1a; 开始学习这个Demo xaml部分 查看MainWindow.xaml&#xff1a; …...

数据湖的整体思路

湖本质上是一个集中化&#xff0c;中心化的&#xff0c;一体化的存储技术&#xff0c;并且在其之上追求技术架构的统一化&#xff0c;如流批一体&#xff0c;服务分析一体化。 当数据湖成为中心&#xff0c;那么就可以围湖而建“数据服务环”&#xff0c;环上的服务包括了数仓、…...

51单片机 跑马灯

#include <reg52.h>//毫秒级延时函数 void delay(int z) {int x,y;for(x z; x > 0; x--)for(y 114; y > 0 ; y--); }sbit LED1 P1^0x0; sbit LED2 P1^0x1; sbit LED3 P1^0x2; sbit LED4 P1^0x3; sbit LED5 P1^0x4; sbit LED6 P1^0x5; sbit LED7 P1^0x6; s…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...