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

【C++STL :vector类 (一) 】详解vector类的使用层vector实践:算法题

 

🔥艾莉丝努力练剑:个人主页

专栏传送门:《C语言》《数据结构与算法》C/C++干货分享&学习过程记录Linux操作系统编程详解笔试/面试常见算法:从基础到进阶

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬艾莉丝的简介:


🎬艾莉丝的C++专栏简介:


目录

C++的两个参考文档

1  ~>  vector容器

1.1  vector的接口数比string类少

1.2  vector的介绍

1.3  vector的理解

1.4  vector的定义

2  ~>  vector的使用:结合文档

2.1  没有输入输出流,无法cout——自己Print

2.2  迭代器:vector iterator 的使用

2.2.1  概念理解

2.2.2  实践

2.3  vector的空间增长问题

2.3.1  文档接口理解

2.3.2  不同环境下capacity增长倍数问题

2.3.3  reserve:提前将空间设置足够,提高效率

2.3.4  实践

2.4  vector的增删查改

2.4.1  vector也只有尾插和尾删

2.4.2  insert && erase实践

2.5  如果你觉得库里面的不好用可以用自己定义的模版

2.6  简单了解一下emplace

2.6.1  简单了解

2.6.2  对比

2.6.3  实践

3  ~>  vector实践:两道算法题

3.1  只出现一次的数字

3.1.1  代码实现

3.2  杨辉三角

3.2.1  C语言太麻烦!沟槽的二级指针还在追我!

3.2.2  C++的vector——轻松搞定

3.2.3  算法代码实现

4  ~>  本文代码完整展示

4.1  Test.c:

4.2  运行

结尾


C++的两个参考文档

老朋友(非官方文档):cplusplus

官方文档(同步更新):cppreference

vector容器文档链接:vector



1  ~>  vector容器

1.1  vector的接口数比string类少

前面我们解释过,string类比STL诞生要早几年,STL很多容器和string都具有相似性,但是string的很多接口非常鸡肋,而且数量多——一百多个接口,博主也介绍过后面的STL借鉴了string,而且取长补短,接口数量大幅减少,就比如今天我们要正式开始介绍的一个新的容器——vector。

如下图所示,是不是少了很多?而且,有没有感觉这些接口很眼熟?没错,和string非常相似,在底层实现层面会有差异,但是使用层面是差不多的,类似于复用的思想,这也就是为什么我们前面要花那么多的篇幅来详细介绍string类——后面的vector、list...都是差不多的。

1.2  vector的介绍

我们早在介绍STL是什么、怎么学习的那篇博客里面就提到了使用STL的三个境界:能用、明理、能扩展 ,那么下面进入到vector的学习,我们也是按照这个方法。

cplusplus中的vector介绍

1.3  vector的理解

string是字符串,vector则是一个改变数据的顺序容器,其实对应的就是博主之前在用C语言实现初阶的数据结构里面实现过的顺序表。可以理解为C++版本的顺序表。

1.4  vector的定义

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

2  ~>  vector的使用:结合文档

2.1  没有输入输出流,无法cout——自己Print

vector没法cin、cout,我们要想输出结果,就得自己封装一个Print函数——

void Print(const vector<int>& v)
{for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}

写完这个,我们就可以偷个懒,用范围for——

	//范围forfor (auto e : v){cout << e << " ";}cout << endl;

2.2  迭代器:vector iterator 的使用

2.2.1  概念理解

iterator的使用 接口说明
(重点)begin+end获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator
rbegin+rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

2.2.2  实践

代码演示如下——

	vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << "it" << " ";++it;}cout << endl;

这个可以封装到Print函数里面——

调用前面已经封装好的Print函数,构造、输出——

2.3  vector的空间增长问题

2.3.1  文档接口理解

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity

(1)capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。VS是PJ版本STL,g++是SGI版本STL。

(2)reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。

(3)resize在开空间的同时还会进行初始化,影响size。

2.3.2  不同环境下capacity增长倍数问题

我们来测试一下vector的默认扩容机制

// 测试vector的默认扩容机制
void TestVectorExpand()
{size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

vs环境下的运行结果:vs下使用的STL基本是按照1.5倍方式扩容——

making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94
capacity changed: 141

g++的运行结果:linux下使用的STL基本是按照2倍方式扩容——

making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128

VS是按第一次2倍、后面1.5倍进行扩容的——

g++是按2倍进行扩容的——

2.3.3  reserve:提前将空间设置足够,提高效率

如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够,这样就可以避免边插入边扩容导致效率低下的问题了——主要是避免一边插入一边扩容——

// 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
void TestVectorExpandOP()
{vector<int> v;size_t sz = v.capacity();v.reserve(100);   // 提前将容量设置好,可以避免一遍插入一遍扩容cout << "making bar grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

2.3.4  实践

2.4  vector的增删查改

  

vector增删查改接口说明
push_back尾插
pop_back尾删
find查找(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[ ]像数组一样访问

2.4.1  vector也只有尾插和尾删

和string一样,vector也只有尾插和尾删,没有头插和头删,因为要挪动数据,效率太低了——

我们要头插、或者头删和string一样,直接用insert和erase就行啦。

2.4.2  insert && erase实践

2.5  如果你觉得库里面的不好用可以用自己定义的模版

这个要当心,这个如果不用就注释掉,否则会跟库冲突——

2.6  简单了解一下emplace

2.6.1  简单了解

emplace可以简单理解为功能和insert差不多,而emplace_back和push_back功能一样,但前者效果更好,这个emplace我们在C++11会细讲。

2.6.2  对比

上图和下图的差异:传参,推荐用下面的写法——

2.6.3  实践


3  ~>  vector实践:两道算法题

3.1  只出现一次的数字

力扣链接:136. 只出现一次的数字

题目描述:

3.1.1  代码实现

代码演示如下——

class Solution {
public:int singleNumber(vector<int>& nums) {int value = 0;for(auto e : nums){//异或value ^= e;cout << endl;}return value;}
};

时间复杂度:O(n),空间复杂度:O(1)

3.2  杨辉三角

力扣链接:118. 杨辉三角

题目描述:

3.2.1  C语言太麻烦!沟槽的二级指针还在追我!

麻不麻烦?麻烦!我们如果用C语言来实现的话,就要动态开辟二维数组——开辟指针数组,这个指针数组是指向数组的指针,或者这样理解:这个数组里面存放了指向数组的指针。

3.2.2  C++的vector——轻松搞定

不用指针,用容器怎么表示二维数组呢?vector<vector<int>>——

3.2.3  算法代码实现

代码演示如下——

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;//定义行vv.resize(numRows,vector<int>());//定义列for(size_t i = 0;i < numRows;++i){vv[i].resize(i + 1,1);//1}for(size_t i = 2;i < vv.size();++i)//第0、1行的都不需要处理,1{for(size_t j = 1;j < vv[i].size() - 1;++j){vv[i][j] = vv[i-1][j] + vv[i-1][j-1];}}return vv;}
};

时间复杂度:O(n),空间复杂度:O(1)


4  ~>  本文代码完整展示

4.1  Test.c:

#define  _CRT_SECURE_NO_WARNINGS  1
#include<iostream>
#include<vector>
using namespace std;void Print(const vector<int>& v)
{for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;////范围for//for (auto e : v)//{//	cout << e << " ";//}//cout << endl;////vector<int>::const_iterator it = v.begin();//while (it != v.end())//{//	cout << "it" << " ";//	++it;//}//cout << endl;
}void Test_vector1()
{//构造vector<int> v1;//空vector<int>v2(10, 1);vector<int>v3(v2.begin(),v2.end());//迭代器string s1("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");vector<int>v4(s1.begin(), s1.end());vector<int>v5(v3);//vector<int> v6({ 1,2,3,4,5,6 });vector<int> v6 = { 1,2,3,4,5,6 };vector<int> v7 = { 1,2,3,4,5,6,1,1,1,1,1,1 };Print(v2);Print(v4);Print(v6);Print(v7);auto il = { 10,20,30,1,2,2 };for (auto e : il){cout << e << " ";}cout << endl;
}void Test_vector2()
{vector<int> v1;//count int n = 1000000000000;const int n = 100;/*v1.reserve(n);*/size_t old = v1.capacity();/*cout << v1.capacity() << endl;*/size_t begin = clock();for (size_t i = 0; i < n; i++){v1.push_back(i);if (old != v1.capacity()){cout << v1.capacity() << endl;old = v1.capacity();}}size_t end = clock();cout << end - begin << endl;vector<int> v2;v2.resize(100.1);Print(v2);
}void Test_vector3()
{vector<int> v1 = { 1,2,3,4,5 };v1.push_back(6);Print(v1);v1.insert(v1.begin(), 0);Print(v1);v1.insert(v1.begin() + 3, 0);Print(v1);v1.erase(v1.begin());Print(v1);v1.erase(v1.begin() + 3);Print(v1);
}//struct在C++里面也是类
struct AA
{int _a1 = 1;int _a2 = 1;AA(int a1 = 1,int a2 = 1):_a1(a1),_a2(a2){ }
};////模版
//template<class T>
//class vector
//{
//private:
//	T* _a;
//	size_t _size;
//	size_t _capacity;
//};void Test_vector4()
{AA aa1 = { 0,0 };vector<AA> v = { aa1,{1,1},{2,2},{3,3} };auto it = v.begin();while (it != v.end()){cout << it->_a1 << ":" << it->_a2 << endl;++it;}cout << endl;//传AA对象v.push_back(aa1);v.emplace_back(aa1);//传构造AA对象的参数v.emplace_back(1, 1);v.push_back({ 2,2 });it = v.begin();while (it != v.end()){cout << it->_a1 << ":" << it->_a2 << endl;++it;}cout << endl;
}int main()
{//Test_vector1();//Test_vector2();/*Test_vector3();*/Test_vector4();return 0;
}

4.2  运行


结尾

往期回顾:

【C++STL :string类 (二) 】从接口应用到内存模型的全面探索

【C++STL:string类(一)】最高效的STL学习法:从string类开始,教你如何阅读官方文档

结语:都看到这里啦!那请大佬不要忘记给博主来个“一键四连”哦!

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡

૮₍ ˶ ˊ ᴥ ˋ˶₎ა

http://www.dtcms.com/a/422473.html

相关文章:

  • 机器学习项目结构目录的构建
  • 2022 年 CSP-J(中国计算机学会软件能力认证入门级)初赛真题与答案解析
  • 常州市建设工程网站衡水做网站
  • 北京58网站建设wordpress在线商城插件
  • 2025年计算机网络与信号处理国际会议(CNSP 2025)
  • 利用css的动画效果制作轮播图
  • docker镜像和
  • CSS通用优惠券样式
  • STM32F1学习——CAN外设(上)
  • Docker Desktop实战、问题记录
  • 《 Linux 点滴漫谈: 二 》全面掌握 Linux 系统安装与环境准备,迈出学习第一步
  • 从0死磕全栈之Next.js 中的 CSS 方案全解析:Global CSS、CSS Modules、Tailwind CSS 怎么选?
  • 先域名 还是先做网站蜘蛛搜索引擎
  • 《C++进阶之C++11》【可变参数模板 + emplace接口 + 新的类功能】
  • 什么网站可以做兼职怎么做提卡网站
  • 【Linux基础知识系列:第一百四十四篇】使用find命令查找和处理文件
  • cocos 武器攻击敌人后 将碰撞node传给角色脚本 有角色脚本传递计算伤害 调用敌人脚本 敌人自己计算血量 如果超过最大血量 自己删除
  • PySide6 主窗口(QMainWindow)菜单(QMenu)实现打开并读取文本文件
  • Steam秋季特卖倒计时!用UU远程国庆随时购史低游戏!
  • Linux系统C++开发环境搭建工具(一)—— gflags/gtest/spdlog 使用指南
  • MySQL逻辑备份工具mysqldump:原理剖析与实操指南
  • Java-Spring入门指南(十一)代理模式与Spring AOP实战
  • 实名认证接口-识破虚假身份:科技为信任筑起第一道防线
  • 柘林网站建设wordpress改背景图片
  • RokcetMQ事务消息详解
  • Athena + S3 数据分析实战(深度版):从数据湖到可视化 BI
  • IP纯净度检测工具
  • 第四部分:VTK常用类详解(第114章 vtkStreamTracer流线追踪类)
  • MATLAB的CFAR(恒虚警率)图像目标检测
  • 2025三掌柜赠书活动第三十五期 AI辅助React Web应用开发实践:基于React 19和GitHub Copilot