当前位置:首页 » 《关注互联网》 » 正文

【C++】vector使用详解以及动态二维数组

18 人参与  2024年11月16日 17:21  分类 : 《关注互联网》  评论

点击全文阅读


目录

1.vector的介绍及使用

2.vector的构造函数、析构函数和operator=

3.vector的遍历

3.1 下标遍历

3.2 迭代器

3.3 范围for

4.reserve

5.resize

6.insert和erase

7.vector支持流插入和流提取吗?

8.动态二维数组

1. vector>剖析

 2. 动态二维数组的访问

3. 动态二维数组的遍历

4. 相关练习-杨辉三角


         本篇我们来介绍STL的vector的内容。vector其实就是顺序表,vector的学习还是分为接口使用和模拟实现两大部分,本片就是介绍一下vector的使用。

1.vector的介绍及使用

vector文档介绍:vector - C++ Reference  在使用时需要加头文件#include <vector>.

vector是一个标准的模板。不知道什么是模板去看【C++】模板(初识):函数模板、类模板-CSDN博客

第一个模板参数是要存的数据类型,第二个模板参数是一个空间配置器,就是一个内存池,现在不用关心他是什么。 

我们在vector学习时一定要学会查文档。

string因为一些发展历史的原因,设计的接口比较多,比较冗余,vector相对来说就好很多,接口比string少很多。我们还是重点说经常使用的接口。

2.vector的构造函数、析构函数和operator=

构造函数

比如说下面的存int类型的顺序表。

vector<int> v1; //无参构造vector<int> v2(10, 1); //10个1初始化vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化vector<int> v4(++v2.begin(), --v2.end());//迭代器区间初始化

析构函数自动调用。

 

赋值运算符重载。

vector<int> v1; //无参构造vector<int> v2(10, 1); //10个1初始化vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化vector<int> v4(++v2.begin(), --v2.end());//迭代器区间初始化v4 = v2; //v2,v4已存在,是赋值

3.vector的遍历

vector的遍历和string一样有三种方式:下标遍历、迭代器、范围for。这三种遍历详细的介绍在string类里面【C++】string类接口使用(万字详解)_sting怎么用-CSDN博客 第2.5节(string类对象的访问及遍历操作),不管是string还是vector,迭代器和范围for的用法都是一样的,类域不同而已,如果不清楚的建议先看string的2.5节。

3.1 下标遍历

vector<int> v2(10, 1); //10个1初始化for (int i = 0; i < v2.size(); i++){cout << v2[i] << " ";}cout << endl;

因为vector也重载了operator[],所以也可以通过下标遍历。

3.2 迭代器

vector<int> v2(10, 1); //10个1初始化vector<int>::iterator it = v2.begin();while (it != v2.end()){cout << *it << " ";++it;}cout << endl;

这里vector的迭代器要指定vector::类域,我们说string的迭代器的时候也是指定了string::类域。

反向迭代器和const迭代器就不演示了。 

3.3 范围for

vector<int> v2(10, 1); //10个1初始化for (auto e : v2){cout << e << " ";}cout << endl;

 

4.reserve

这个部分别的接口就不多说了,看一眼就知道是什么。我们来说一下reserve扩容。

 用法大家都知道,我们看一下扩容机制,是不是一直按1.5倍扩。

void TestVectorExpandOP(){vector<int> v;size_t sz = v.capacity();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';}}}int main(){TestVectorExpandOP();return 0;}

大概是1.5倍,有的地方做了特殊处理,比如向上取整,向下取整。

解决办法就是提前开空间,提前就开100个。

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';}}}

同样的,我们传n过去,编译器会开大于等于n的空间。

但是对于下面的第二种情况,string和vector处理方式不同。

5.resize

reserve是绝对不会改变size的,只会对capacity产生影响,但是resize会改变size,还会改变capacity。

 第二个参数val传的话,多出来的所有都存为val。直接代码演示。

vector<int> v(10, 1);//10个1初始化v.resize(5); //n<size情况

vector<int> v(10, 1);//10个1初始化v.reserve(20);//开20个空间//size < n < capacity,不传第二个参v.resize(15); 

vector<int> v(10, 1);//10个1初始化v.reserve(20);//开20个空间//size < n < capacity,传第二个参v.resize(15, 2); 

vector<int> v(10, 1);//10个1初始化v.reserve(20);//开20个空间//n > capacity,不传第二个参v.resize(23); 

vector<int> v(10, 1);//10个1初始化v.reserve(20);//开20个空间//n > capacity,传第二个参v.resize(23, 2); 

 resize大概就是这样。

6.insert和erase

尾插和尾删就不多说了,这里说一下insert。

vector的insert不支持下标了,都是迭代器。

vector<int> v(10, 1);v.insert(v.begin(), 2);//头插v.insert(v.end(), 3);//尾插

vector<int> v(10, 1);v.insert(v.begin(), 2);//头插v.insert(v.end(), 3);//尾插v.insert(v.begin() + 3, 4);//第3个位置插入

 erase也不支持下标,只支持迭代器。

vector<int> v(10, 1);v.insert(v.begin(), 2);//头插v.insert(v.end(), 3);//尾插v.insert(v.begin() + 3, 4);//第3个位置插入v.erase(++v.begin());//删第2个位置数据

 

7.vector支持流插入和流提取吗?

不支持。我们会发现vector文档里面并没有重载<<和>>,因为vector的输入输出有很多不确定性。

这个要注意一下。

        vector是模板,所以模板参数可以是任何类型,包括vector里面存string,vector里面存vector。

8.动态二维数组

vector<vector>其实就是一个动态二维数组。

1. vector<vector<int>>剖析

假设vector里的成员变量是_a,_size,_capacity,_a指向一个数组。

00e1821fcba94abc9d46ad553a4d0287.png

假如我们模板参数传int,就是vector<int>,那么_a就是int*类型的参数,数组里面存的就是int类型的数据。

bc584099f45c40998e75f9d002cfb90e.png

如果我们模板参数传vector<int>,就是vector<vector<int>>,那么_a就是vector<int>*类型的参数,数组里面存的就是vector类型的数据。

6dbab57e0cc94caa8dbd2d6d9c8d5468.png

数组里的vector里面也有_a,_size,_capacity。

239b86e44f904534981c3712c1a2601d.png

数组里面的_a是int*类型,指向int类型的数组。

35d40d068159414d81ff6a1cb464ac69.png

现在这里有个动态二维数组。

//10*5的二维数组vector<int> v(5, 1);vector<vector<int>> vv(10, v);

 首先就是vector<vector<int>> vv(10, v);用10个v初始化,10就是10行;v又是用5个1初始化的,5就是5列。

16f3e0194f744514978959b2b6b61967.png
我们说了vector是模板,所以这个动态二维数组其实是实例化了两个类,一个是vector<int>,一个是vector<vector<int>>,编译器通过模板生成的类大概像下面两个这样。

eb863e336c384ff09c9ca4bf08dc1fa1.png

 2. 动态二维数组的访问

 想访问这个二维数组的话,直接方括号[]访问就行。

//10*5的二维数组vector<int> v(5, 1);vector<vector<int>> vv(10, v);vv[2][1] = 2;//访问第2行第二列,改变它的值

两个[]调用的不是同一个类,是两个不同的类,模板通过不同参数实现的那两个不同的类。

3. 动态二维数组的遍历

动态二维数组遍历用到的是下标遍历,此时迭代器、范围for都不好使。

for (size_t i = 0; i < vv.size(); i++){for (size_t j = 0; j < v.size(); j++){cout << vv[i][j] << " ";}cout << endl;}

cbbd59aff99c4c86a668baa9a343684a.png

4. 相关练习-杨辉三角

118. 杨辉三角 - 力扣(LeetCode)

 这个题就是需要用到动态数组,静态数组完成不了。

numRows是行数,我们先开行的空间。

class Solution {public:    vector<vector<int>> generate(int numRows) {        vector<vector<int>> vv(numRows); //行        }};

通过观察我们也可以发现,列数等于行数+1,比如第0行有1列,第1行有2列。用resize开空间,不用reserve,因为我们不仅要改变capacity的大小,还要size也变化。

vector<vector<int>> generate(int numRows) {      vector<vector<int>> vv(numRows); //行      for (size_t i = 0; i < vv.size(); i++)      {          vv[i].resize(i + 1, 1);//列,全初始化为1      }}

接下来就是改变三角形里面的值。从2行开始。

5c0526c751264d438352c94e6c8cb2af.png

class Solution {public:    vector<vector<int>> generate(int numRows) {        vector<vector<int>> vv(numRows); //行        for (size_t i = 0; i < vv.size(); i++)        {            vv[i].resize(i + 1, 1);//列        }        for (size_t i = 2; i < vv.size(); i++)        {            for (size_t j = 0; j < vv[i].size()-2; j++)            {                vv[i][j+1] = vv[i-1][j] + vv[i-1][j+1];            }        }        return vv;    }};

最后返回vv就可以了。

别的接口就不多说了,很多和string接口用法一致。所以一定要打好string的基础,vector学起来就比较轻松。【C++】string类接口使用(万字详解)_sting怎么用-CSDN博客


点击全文阅读


本文链接:http://zhangshiyu.com/post/187269.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1