【STL模版库】vector介绍及使用 {构造函数,迭代器,容量相关接口,增删查改;动态二维数组}

news/2024/11/25 13:21:09/

一、vector的介绍

在这里插入图片描述

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
  3. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因此存储空间比实际需要的空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  4. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。

二、vector的使用

vector和string的底层都是顺序表,且由于STL库函数的设计互通,因此使用也类似。

所以相关函数的使用细节可以参考文章:【STL模版库】string类:常用接口函数

下面的内容只做简介,不再做详细介绍。

2.1 构造函数

在这里插入图片描述


2.2 迭代器

在这里插入图片描述

在这里插入图片描述


2.3 容量相关接口

在这里插入图片描述

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

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

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

在这里插入图片描述


2.4 增删查改

在这里插入图片描述

  • 下面重点介绍的find、sort和swap函数都是由算法模块实现的函数模版,并不是vector的成员接口。
  • 在使用前需要包含头文件<algorithm>,并展开std命名空间。

2.4.1 find

在这里插入图片描述

此函数模版的行为等效于:

template<class InputIterator, class T>InputIterator find (InputIterator first, InputIterator last, const T& val)
{while (first!=last) {if (*first==val) return first;++first;}return last;
}
  • find仅仅是一个函数模版,会根据传入参数的不同类型实例化出适应各种类型的find函数。
  • 这里使用迭代器遍历容器,是因为迭代器是所有容器的通用遍历访问方法。
  • 使用引用传参避免发生拷贝构造,更高效。
  • 如果找到了,返回对应元素的迭代器;如果找不到,返回last;

其他查找函数

find_if

功能:返回范围中第一个满足指定条件的元素的迭代器

参数:共有3个,前两个参数是待查找的迭代器区间;最后一个参数是一个返回值为bool类型的一元函数指针,该函数用于条件判断。

同类函数:find_if_not,与find_if逻辑相反,参数和使用方法相同。

find_first_of

功能:在母序列中从前往后查找子序列,返回母序列中第一次出现子序列的首元素的迭代器

参数:共有5个,前两个参数是母序列迭代器区间;中间两个是子序列迭代器区间;最后一个参数是一个返回值为bool类型的二元函数指针,该函数用于条件判断。

同类函数:find_end,与find_first_of查找方向相反是从后往前查找,参数和使用方法相同。


2.4.2 sort

在这里插入图片描述

C++STL库中的sort接口底层采用快速排序实现。

#include <iostream>
#include <algorithm> //sort
#include <functional> //greater
using namespace std;int main(){string s("hello412535");sort(s.begin(), s.end()); //第三个参数缺省默认排升序;//sort(s.begin(), s.end(), less<char>()); //也可以显示的传less也是排升序;for(auto e : v1){cout << e << " ";}cout << endl;sort(s.begin(), s.end(), greater<char>()); //传greater是排降序;for(auto e : v1){cout << e << " ";}cout << endl;return 0;
}

前两个参数同样是待排序的迭代器区间范围

第三个参数缺省默认升序,传less是升序排序,传greater是降序排序。

注意:

  • 这里的greater和less是类模版。
  • 传入的less<char>()和greater<char>()是实例化出的模版类定义的匿名对象。
  • 要使用greater类模版需要包<functional>头文件

2.4.3 swap

在这里插入图片描述

此函数模版的行为等效于:

template <class T> void swap ( T& a, T& b )
{T c(a); a=b; b=c;
}
  • 由此可见,算法模块中实现的swap函数模版,采用的是创建临时变量,赋值交换的方法。仅仅适用于内置类型,而对于自定义类型会进行1次拷贝构造和2次赋值拷贝。尤其针对需要进行深拷贝的对象,这种交换方式的效率极低。

  • 因此,对于需要进行交换操作的自定义类型一般会自己实现成员交换函数,只对成员变量进行浅交换即可。


三、动态二维数组

vector不仅可以存储内置类型,还可以用于存储自定义类型如:vector<string>和vector<vector<int>>

3.1 vector<string>

vector<char> 能否替代 string?

回答:不能

  1. string字符串由’\0’结尾,而vector<char>不会。
  2. string类重载了流插入<<和流提取>>运算符,能更加方便的进行输入输出。
  3. string类中还提供了操作字符串的专用接口,如operator+=、字符串比较大小、to_string等等。
  4. 因此vector<char> 不能替代 string
int main(){vector<string> strv;string str1("张三");strv.push_back(str1);strv.push_back(string("李四")); //[1]strv.push_back("王五"); //[2]for(const auto &name : strv) //[3]{cout << name << endl;}
}

解释:

  • [1] 定义匿名对象,匿名对象的生命周期只在当前行。
  • [2] 由于string类中定义了一个单参构造函数string (const char* s);,所以常量字符串"王五"可以进行隐式类型转换,构造临时string对象。
  • [2] 类型转换形成的临时对象具有常性,而void push_back (const value_type& val);的参数类型是常引用,因此这种写法可行。
  • [3] 范围for中的临时变量的类型建议写成引用,这是因为如果是普通变量会进行频繁地拷贝构造(尤其针对自定义类型),效率极低。如果循环中不做修改建议加const进行保护。

3.2 vector<vector<int>>

以题目【Leetcode.118】杨辉三角为例:

在这里插入图片描述

题解:

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv; //使用vector定义二维数组vv,vv中的每个元素都是vector<int>vv.resize(numRows); //[1]for(size_t i = 0; i<vv.size(); ++i){vv[i].resize(i+1); //[2]vv[i].front() = 1;vv[i].back() = 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]; //[3]}}return vv;}
};

解释:

  • [1] 为vector<vector>对象开空间并初始化。

  • [1] 这是resize的函数原型:void resize (size_type n, value_type val = value_type());

  • [1] 第二个参数用value_type类型的匿名对象做缺省值,相当于调默认构造生成临时对象。

  • [1] resize函数内利用临时对象拷贝构造生成新对象。

  • [1] 因此执行过这条resize语句之后的结构为:设numRows==5
    在这里插入图片描述

  • [2] 为每个vector元素开空间并初始化,然后将每行的第一列和最后一列置为1。

  • [3] vector<vector>动态二维数组的访问:先后调用两个operator[]的重载函数,实现了二维数组的访问遍历。
    在这里插入图片描述

  • [3] 还记得普通二维数组的访问方式吗?二维数组在内存中和一维数组一样是线性连续存储的,编译器会先将两个二维下标换算成一个一维下标,然后才能通过解引用访问。

  • 最后生成的二维数组结构图示
    在这里插入图片描述

  • 关于二维动态数组的深拷贝问题我会在下一节进行详解:【STL模版库】模拟实现vector类模版6.2


http://www.ppmy.cn/news/83509.html

相关文章

springBoot中使用redis实现分布式锁实例demo

首先 RedisLockUtils工具类 package com.example.demo.utils;import org.junit.platform.commons.util.StringUtils; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.red…

Revit建模|怎么创建轴网标高?

大家好&#xff0c;这里是建模助手&#xff0c;今天给大家讲一讲怎么创建轴网标高。 标高用来定义楼层层高以及生成平面视图&#xff0c;轴网用于为构件定位&#xff0c;在Revit中轴网确定了一个不可见的工作平面&#xff0c;轴网编号以及标高符号样式均可定制修改。目前&…

MySQL8.0高级篇(上)-架构与索引

文章目录 一、MySQL环境安装与介绍1、MySQL安装1.1 安装前说明1.2 MySQL的Linux版安装1.3 MySQL登录1.4 字符集的相关操作1.5 字符集与比较规则(了解)1.6 请求到响应过程中字符集的变化1.7 SQL大小写规范1.8 sql_mode的合理设置 2、MySQL的数据目录2.1 MySQL8的主要目录结构2.2…

Azure Services -5.25-summary

文章目录 1. Resources2.Data processing process3.Virtual network and public ip address4. Kubernetes services5. Yaml file first , we enter the homepage of microsoft azure, and we can see a lot of servicse provided by the microsoft azure , 1. Resources accou…

嘉兴桐乡技能培训-平面设计入门看过来

想要当一个设计师&#xff0c;首先要确定自己是否有学习的耐心和勇气。所有学科的新人成长都需要一个过程&#xff0c;这自然要从模仿开始。要多看优秀的设计作品&#xff0c;学习人家作品中优秀的地方&#xff0c;并且多多练习&#xff0c;不断地进步&#xff0c;不断地提高自…

Mac 原神电脑版下载安装使用教程,MacBook 上也可以玩原神了

最近发现了一个很棒的工具&#xff0c;他可以让你的 Mac 苹果电脑运行原神&#xff0c;而且画质和流畅度都是在线的&#xff0c;今天分享给大家 软件名字叫 playCover &#xff0c;根据作者的介绍这款软件最初就是国外的一位博主想在 Mac 上玩原神特意开发的一款软件&#xff…

uniapp实现微信小程序的电子签名

签名页的效果如图下所示&#xff1a; 封装的组件代码如下所示&#xff1a; <template><view><view class"wrapper"><view class"handBtn"><button click"handleReset" class"delBtn">清除</button&…

版图设计工具解析-virtuoso的display.drf文件解析

1. display.drf文件解析 virtuoso的版图颜色定义分析 下图为virtuoso的版图颜色&#xff0c;包括填充&#xff0c;轮廓&#xff0c;彩点&#xff0c;线形 本文以smic18mmrf的display.drf文件进行解析 smic18的PDK包下存在display.drf文件 打开文件display.drf文件后看到如下…