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

《C++ STL:vector类(上)》:详解基础使用核心接口及经典算法题

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》《优选算法指南-必刷经典100题》

🌟心向往之行必能至


🎬博主简介:

前言:

在vector类学习之前,大家可以回顾下string类的实现,可以发现我们string类的接口有很多,而vector类的接口比string少了很多,string类比STL诞生要早几年,STL很多容器和string都具有相似性,但是string的很多接口非常鸡肋


目录

前言:

一、vector容器

1.1vector的介绍

1.2对vector的理解

1.3vector的定义

二、vector的使用(结合文档)

2.1无输入输出流——自己实现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  实践

三、vector实践:两道算法题

3.1  只出现一次的数字

代码实现

3.2  杨辉三角

C版本:

 C++版本的vector——轻松搞定

算法代码实现

本文代码完整展示

Test.c:

结尾


一、vector容器

1.1vector的介绍

cplusplus中vector类介绍

1.2对vector的理解

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

1.3vector的定义

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

二、vector的使用(结合文档)

2.1无输入输出流——自己实现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函数里面

void Print(const vector<int>& v)
{//for (size_t i = 0; i < v.size(); i++)//{//	cout << v[i] << ' ';//}//cout << endl;//for (auto e : v)//{//	cout << e << ' ';//}//cout << endl;vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << ' ';++it;}cout << endl;
}

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

void test_vector1()
{vector<int> v1;vector<int> v2(10, 1);vector<int> v3(v2);vector<int> v4(v3.begin(), v3.end());string s1("xxxxxxxx");vector<int> v5(s1.begin(), s1.end());vector<int> v6 = { 1,2,3,4,5 };Print(v2);Print(v5);Print(v6);auto il = { 1,2,3,4 };for (auto e : il){cout << e << " ";}cout << endl;
}

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

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  实践
void test_vector2()
{//vector<int> v1;//v1.reserve(100);//size_t old = v1.capacity();//cout << v1.capacity() << endl;//for (size_t i = 0; i < 100; i++)//{//	v1.push_back(i);//	if (old != v1.capacity())//	{//		cout << v1.capacity() << endl;//		old = v1.capacity();//	}//}vector<int> v1;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);
}

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实践
void test_vector3()
{vector<int> v1 = { 1,2,3 };v1.push_back(4);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);}

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

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

2.6  简单了解一下emplace

2.6.1  简单了解

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

2.6.2  对比

2.6.3  实践
void test_vector4()
{AA aa1 = { 0,0 };vector<AA> v1 = { aa1,{1,1},{2,2},{3,3} };auto it = v1.begin();while (it != v1.end()){cout << it->_a1 << ' ' << it->_a2 << endl;++it;}cout << endl;v1.push_back(aa1);v1.emplace_back(aa1);//差异v1.push_back({ 1, 1 });//既可以传AA对象,又可以传构造AA对象的参数v1.emplace_back(2, 2);//只能传AA对象it = v1.begin();while (it != v1.end()){cout << it->_a1 << ' ' << it->_a2 << endl;++it;}cout << endl;
}


三、vector实践:两道算法题

3.1  只出现一次的数字

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

题目描述:

题目示例:

代码实现

代码演示如下

class Solution {
public:int singleNumber(vector<int>& nums) {int val=0;for(auto e:nums){val^=e;}     return val;}
};

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

3.2  杨辉三角

力扣链接:118. 杨辉三角

题目描述:

题目示例:

C版本:

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

 C++版本的vector——轻松搞定

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

算法代码实现

代码:

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)。

本文代码完整展示

Test.c:

#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 (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);vector<int> v4(v3.begin(), v3.end());string s1("xxxxxxxx");vector<int> v5(s1.begin(), s1.end());vector<int> v6 = { 1,2,3,4,5 };Print(v2);Print(v5);Print(v6);auto il = { 1,2,3,4 };for (auto e : il){cout << e << " ";}cout << endl;
}void test_vector2()
{//vector<int> v1;//v1.reserve(100);//size_t old = v1.capacity();//cout << v1.capacity() << endl;//for (size_t i = 0; i < 100; i++)//{//	v1.push_back(i);//	if (old != v1.capacity())//	{//		cout << v1.capacity() << endl;//		old = v1.capacity();//	}//}vector<int> v1;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 };v1.push_back(4);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 AA {int _a1 = 1;int _a2 = 1;AA(int a1 = 1, int a2 = 1):_a1(a1), _a2(a2){}
};void test_vector4()
{AA aa1 = { 0,0 };vector<AA> v1 = { aa1,{1,1},{2,2},{3,3} };auto it = v1.begin();while (it != v1.end()){cout << it->_a1 << ' ' << it->_a2 << endl;++it;}cout << endl;v1.push_back(aa1);v1.emplace_back(aa1);//差异v1.push_back({ 1, 1 });//既可以传AA对象,又可以传构造AA对象的参数v1.emplace_back(2, 2);//只能传AA对象it = v1.begin();while (it != v1.end()){cout << it->_a1 << ' ' << it->_a2 << endl;++it;}cout << endl;
}//template<class T>
//class vector {
//paivate:
//	T* _str;
//	size_t size;
//	size_t capacity;
//};int main()
{test_vector4();return 0;
}

结尾

往期回顾:

《一篇拿下C++:string类(详解版)》:教你如何从入门到避坑再到玩转字符串问题

总结:这篇博客到此为止,给大家分享了vector类的接口使用,那么下篇博客我将给大家分享vector的底层,如果这篇文章对你有帮助的话,可以给博主一键四连哦

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

相关文章:

  • osg中相机矩阵到vsg相机矩阵的转换
  • 怎么给网站做seo上海中风险地区什么时候能解除
  • 在IDEA中使用Git
  • IntelliJ IDEA 2025:最新使用图文教程!
  • 十二、SpringMVC
  • 公司营销型网站建设成都建站seo
  • 什么是GO语言里面的GMP调度模型?
  • Traffic Filtering 流过滤 概念及题目
  • 198种组合算法+优化BiGRU双向门控循环单元+SHAP分析+新数据预测+多输出!深度学习可解释分析,强烈安利,粉丝必备!
  • 兼职开发网站开发建设网站需要学什么
  • SQLite 简介
  • TypeScript 中的 JSX 详解
  • Codesys如何读取轴的当前控制模式
  • 高性能网站建设指南 京东模拟网站开发
  • 一元购网站建设教育类网站策划书
  • 2025 AI 落地全景:从技术热潮到产业重构
  • 解析动态数据:如何抓取 JavaScript 加载的 AJAX 内容
  • 聚焦技术落地,展现 AI 重构产业的实践路径。
  • 番禺网站(建设信科网络)小卖部做网站
  • 【氮化镓】P-GaN:提高高温栅极寿命的解决方案
  • 商洛做网站多少钱珠海网站制作哪家便宜
  • 唐山中企动力做网站用php做电子商务网站
  • 05_Pandas数据结构
  • OSPF协议详解3:网络类型、SPF算法、路由选择与特殊区域
  • 10.3总结
  • 算法比赛中的浮点数精度陷阱:从一个货币分解问题说起
  • 昆明手机网站开发不到网站是为什么
  • 反爬虫机制深度解析:从基础防御到高级对抗的完整技术实战
  • 爬坑 10 年!京东店铺全量商品接口实战开发:从分页优化、SKU 关联到数据完整性闭环
  • LeetCode每日一题——判断能否形成等差数列