浅谈C++|STL之vector篇

一.vector的基本概念
vector是C++标准库中的一种动态数组容器,提供了动态大小的数组功能,能够在运行时根据需要自动扩展和收缩。vector以连续的内存块存储元素,可以快速访问和修改任意位置的元素。以下是
vector的基本概念和特点:
动态大小:
vector可以动态地调整其大小,可以在运行时根据需要添加或删除元素。与静态数组不同,vector不需要在定义时指定固定的元素个数。连续存储:
vector以连续的内存块存储元素。这样的存储方式使得访问元素变得高效,可以通过索引快速访问和修改任意位置的元素。自动扩展和收缩:
vector可以根据需要自动扩展以容纳更多的元素,并在需要时自动收缩以节省内存。这样,您无需手动管理内存,vector会自动处理。插入和删除:
vector提供了多种方法来插入和删除元素。可以在任意位置插入元素,也可以从任意位置删除元素,包括头部和尾部。随机访问:
vector支持快速的随机访问。可以使用索引来直接访问任意位置的元素,时间复杂度为O(1)。迭代器支持:
vector提供迭代器来遍历容器中的元素。迭代器可以用于读取和修改容器中的元素,支持正向和反向迭代。
vector是一个非常常用和灵活的容器,适用于需要动态调整大小的数组存储需求。它在许多应用中都很有用,例如数据的动态收集、动态分配的数组、实现栈和队列等。
功能:
vector教据结构和数组非常相似,也称为单端数组
vector与普通数组的区别
不同之处在于数组是静态空间,而vector可以动态扩展
动态扩展
并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
二.vector赋值操作
vector提供了几种不同的函数和操作符用于赋值操作。以下是常用的vector赋值操作的函数原型:
operator=操作符:
vector& operator=(const vector& other);
该操作符用于将一个vector赋值给另一个vector,使它们包含相同的元素。该操作符返回一个引用,允许连续赋值。
assign()函数:
void assign(size_type count, const T& value);
template<typename InputIt>
void assign(InputIt first, InputIt last);
void assign(std::initializer_list<T> ilist);
assign() 函数用于将指定的值、范围或初始化列表中的元素赋值给vector。第一个版本接受指定数量的元素值;第二个版本接受范围指针,可以使用迭代器指定范围;第三个版本接受一个初始化列表。
swap()函数:
void swap(vector& other);
swap() 函数用于交换两个vector的内容,将当前vector与另一个vector的元素进行交换。
整理成表格,以方便查阅。
| 函数 | 函数原型 | 描述 |
|---|---|---|
operator= | vector& operator=(const vector& other); | 将一个vector赋值给另一个vector,使它们包含相同的元素。 |
assign() | void assign(size_type count, const T& value); | 将指定数量的元素值赋值给vector。 |
template<typename InputIt> void assign(InputIt first, InputIt last); | 将范围指针指定的元素赋值给vector。 | |
void assign(std::initializer_list<T> ilist); | 将初始化列表中的元素赋值给vector。 | |
swap() | void swap(vector& other); | 交换两个vector的内容。 |
三.vextor的大小和容量
vector提供了一些函数用于获取容量和大小相关的信息。以下是vector的容量和大小函数的原型:
size()函数:
size_type size() const;
此函数返回vector当前包含的元素数量,也就是vector的大小。
max_size()函数:
size_type max_size() const;
该函数返回vector可以容纳的最大元素数量,考虑到系统限制和内存限制。
resize()函数:
void resize(size_type count);
void resize(size_type count, const T& value);
此函数用于调整vector的大小,可以增加或减少元素的数量。第一个版本将vector的大小调整为指定的 count,第二个版本还可以指定当扩展vector大小时,默认填充的元素值。
capacity()函数:
size_type capacity() const;
该函数返回当前vector的容量,即能够在重新分配内存之前持有的元素数量,以节省内存重新分配的开销。
reserve()函数:
void reserve(size_type new_cap);
此函数用于增加vector的容量,使其至少能够容纳指定数量的元素,但不为元素分配实际值。这可以提前分配所需的内存,以减少因调整大小而引起的内存重新分配的次数。
整理成表格:
| 函数 | 函数原型 | 描述 |
|---|---|---|
size() | size_type size() const; | 返回vector当前包含的元素数量,即vector的大小。 |
max_size() | size_type max_size() const; | 返回vector可以容纳的最大元素数量,受系统限制和内存限制约束。 |
empty() | bool empty() const; | 判断vector是否为空,若为空则返回true,否则返回false。 |
resize() | void resize(size_type count);void resize(size_type count, const T& value); | 调整vector的大小,增加或减少元素数量。第一个版本将 vector的大小调整为指定的count。第二个版本在扩展 vector大小时,指定默认的填充元素值。 |
capacity() | size_type capacity() const; | 返回当前vector的容量,即为元素重新分配内存之前可以容纳的元素数量,以节省内存重新分配的开销。 |
reserve() | void reserve(size_type new_cap); | 增加vector的容量,使其至少能够容纳指定数量的元素,但不为元素分配实际值。这样可以减少内存重新分配的次数。 |
四.vector插入和删除
整理成表格:
| 函数 | 函数原型 | 描述 |
|---|---|---|
insert() | iterator insert(iterator pos, const T& value);iterator insert(iterator pos, size_type count, const T& value); | 在指定位置插入元素到vector中,并返回插入的位置迭代器。第一个版本可以插入单个元素。 第二个版本可以插入指定数量的相同元素。 |
emplace() | template <class... Args> iterator emplace(iterator pos, Args&&... args); | 在指定位置就地构造一个元素,并返回插入的位置迭代器。 |
erase() | iterator erase(iterator pos);iterator erase(iterator first, iterator last); | 从vector中删除指定位置或范围的元素,并返回下一个元素的位置迭代器。 |
clear() | void clear(); | 从vector中移除所有的元素,使其变为空。 |
push_back() | void push_back(const T& value); | 将元素添加到vector的末尾。 |
emplace_back() | template <class... Args> reference emplace_back(Args&&... args); | 在vector的末尾就地构造一个元素。 |
pop_back() | void pop_back(); | 移除vector的最后一个元素。 |
请注意,表中的函数参数使用的是迭代器(iterator),而非常数迭代器(const_iterator)。这是因为插入和删除操作会改变容器的内容,所以需要可变的迭代器来指向和修改元素。
五.vector数据的存取
下面是vector的数据存取操作函数的函数原型整理成表格:
| 函数 | 函数原型 | 描述 |
|---|---|---|
at() | reference at(size_type pos);const_reference at(size_type pos) const; | 返回指定位置的元素的引用。 若 pos超出范围,会抛出out_of_range异常。 |
operator[]() | reference operator[](size_type pos);const_reference operator[](size_type pos) const; | 返回指定位置的元素的引用。 不进行范围检查,使用时需确保索引有效。 |
front() | reference front();const_reference front() const; | 返回vector中第一个元素的引用。 |
back() | reference back();const_reference back() const; | 返回vector中最后一个元素的引用。 |
data() | T* data();const T* data() const; | 返回指向vector中第一个元素的指针。若 vector为空,返回空指针。 |
以上是常用的vector数据存取操作的函数原型。您可以根据需要使用它们来访问和修改vector中的元素。
六.vector的容器交换
vector的容器互换操作可以使用swap()函数来实现。swap()函数可以交换两个容器的内容,具体的函数原型如下:
template <class T, class Alloc>
void swap(vector<T,Alloc>& x, vector<T,Alloc>& y) noexcept;
其中,x和y是要互换内容的两个 vector 容器。使用swap()函数可以快速高效地交换两个 vector 的内容,而不需要逐个元素进行复制或移动。
下面是一个简单的示例演示如何使用 swap() 函数交换两个 vector 的内容:
#include <iostream>
#include <vector>int main() {std::vector<int> vec1 = {1, 2, 3, 4};std::vector<int> vec2 = {5, 6, 7, 8};// 输出交换前的内容std::cout << "vec1: ";for (const auto& num : vec1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "vec2: ";for (const auto& num : vec2) {std::cout << num << " ";}std::cout << std::endl;// 交换容器内容std::swap(vec1, vec2);// 输出交换后的内容std::cout << "vec1: ";for (const auto& num : vec1) {std::cout << num << " ";}std::cout << std::endl;std::cout << "vec2: ";for (const auto& num : vec2) {std::cout << num << " ";}std::cout << std::endl;return 0;
}
运行以上代码,将会输出如下结果:
vec1: 1 2 3 4
vec2: 5 6 7 8
vec1: 5 6 7 8
vec2: 1 2 3 4
通过 swap() 函数,vec1 和 vec2 的内容被互换了。这个操作非常高效,因为只涉及到指针的交换,而不需要逐个元素进行复制或移动。
巧用swap收缩内存空间
swap()函数还可以用于收缩vector内存空间,从而释放不需要的内存。通过将一个空的vector与目标vector进行交换,可以使目标vector的容量缩小到与其当前大小相匹配。
这是因为当swap()函数交换两个vector时,目标vector会获得另一个vector的内存空间,而那个被交换的vector则会获得一个空的内存空间。然后,由于交换后的vector大小与容量相匹配,多余的内存会被释放。
以下是一个示例代码,展示了如何通过swap()函数收缩vector的内存空间:
#include <iostream>
#include <vector>int main() {std::vector<int> vec;// 向vector中添加大量数据for (int i = 0; i < 1000000; ++i) {vec.push_back(i);}std::cout << "Size before shrink: " << vec.size() << std::endl;std::cout << "Capacity before shrink: " << vec.capacity() << std::endl;// 收缩内存空间std::vector<int>(vec).swap(vec);std::cout << "Size after shrink: " << vec.size() << std::endl;std::cout << "Capacity after shrink: " << vec.capacity() << std::endl;return 0;
}
运行以上代码,将会输出如下结果:
Size before shrink: 1000000
Capacity before shrink: 1048576
Size after shrink: 1000000
Capacity after shrink: 1000000
通过使用swap()函数将一个空的vector和目标vector交换,我们成功缩小了vec的内存空间,使其容量与其大小相匹配。注意,swap()函数的参数是通过使用临时vector构造的,以避免影响到原始vec的值。
请注意,这种技巧并不适用于C++11标准之前的版本,因为在C++11之前,vector的移动语义不是必须的,而可能导致复制操作而不是交换操作。因此,在使用旧标准的编译器中,最好使用shrink_to_fit()函数来请求收缩内存,这是C++11引入的函数,并作为标准函数来直接缩小容器的内存空间。
七.函数接口总结
以下是一些对std::vector的扩展函数和成员类型:
| 函数或成员类型 | 描述 |
|---|---|
std::vector::emplace_hint | 在指定位置的提示前插入元素 |
std::vector::insert_or_assign | 插入元素或修改现有元素的值 |
std::vector::erase | 移除指定位置或指定范围的元素 |
std::vector::erase_if | 根据给定的谓词函数删除元素 |
std::vector::remove | 移除指定值的所有元素 |
std::vector::remove_if | 根据给定的谓词函数删除元素 |
std::vector::swap | 交换两个向量的内容 |
std::vector::merge | 合并两个已排序的向量,并将结果存储在第一个向量中 |
std::vector::sort | 对向量的元素进行排序 |
std::vector::stable_sort | 对向量的元素进行稳定排序 |
std::vector::reverse | 反转向量中元素的顺序 |
std::vector::unique | 移除重复的元素,仅保留相邻的一个 |
std::vector::unique | 根据给定的谓词函数移除重复的元素 |
std::vector::binary_search | 使用二分查找在排序的向量中查找元素 |
std::vector::lower_bound | 返回一个迭代器,指向在已排序向量中首次出现不小于给定值的元素位置 |
std::vector::upper_bound | 返回一个迭代器,指向在已排序向量中首次出现大于给定值的元素位置 |
std::vector::equal_range | 返回一个pair,其中第一个迭代器是lower_bound返回值,第二个迭代器是upper_bound返回值 |
std::vector::rbegin | 返回指向最后一个元素的反向迭代器 |
std::vector::rend | 返回指向第一个元素之前位置的反向迭代器 |
std::vector::cbegin | 返回指向第一个元素的常量迭代器 |
std::vector::cend | 返回指向最后一个元素之后位置的常量迭代器 |
std::vector::crbegin | 返回指向最后一个元素的反向常量迭代器 |
std::vector::crend | 返回指向第一个元素之前位置的反向常量迭代器 |
std::vector::max_size | 返回向量能容纳的最大元素数量 |
std::vector::reserve | 提前预留指定的容量,以减少重新分配内存的次数 |
std::vector::emplace_hint | 在指定位置的提示前插入元素 |
std::vector::insert_or_assign | 插入元素或修改现有元素的值 |
std::vector::get_allocator | 返回与向量关联的内存分配器 |
std::vector::operator== | 判断两个向量是否相等 |
std::vector::operator!= | 判断两个向量是否不相等 |
std::vector::operator< | 比较两个向量的字典序 |
std::vector::operator<= | 判断一个向量是否小于等于另一个向量 |
std::vector::operator> | 判断一个向量是否大于另一个向量 |
std::vector::operator>= | 判断一个向量是否大于等于另一个向量 |
std::vector::emplace_hint | 在指定位置的提示前插入元素 |
std::vector::insert_or_assign | 插入元素或修改现有元素的值 |
std::vector::erase | 移除指定位置或指定范围的元素 |
std::vector::erase_if | 根据给定的谓词函数删除元素 |
std::vector::remove | 移除指定值的所有元素 |
std::vector::remove_if | 根据给定的谓词函数删除元素 |
std::vector::swap | 交换两个向量的内容 |
std::vector::merge | 合并两个已排序的向量,并将结果存储在第一个向量中 |
std::vector::sort | 对向量的元素进行排序 |
std::vector::stable_sort | 对向量的元素进行稳定排序 |
std::vector::reverse | 反转向量中元素的顺序 |
std::vector::unique | 移除重复的元素,仅保留相邻的一个 |
std::vector::unique | 根据给定的谓词函数移除重复的元素 |
std::vector::binary_search | 使用二分查找在排序的向量中查找元素 |
std::vector::lower_bound | 返回一个迭代器,指向在已排序向量中首次出现不小于给定值的元素位置 |
std::vector::upper_bound | 返回一个迭代器,指向在已排序向量中首次出现大于给定值的元素位置 |
std::vector::equal_range | 返回一个pair,其中第一个迭代器是lower_bound返回值,第二个迭代器是upper_bound返回值 |
相关文章:
浅谈C++|STL之vector篇
一.vector的基本概念 vector是C标准库中的一种动态数组容器,提供了动态大小的数组功能,能够在运行时根据需要自动扩展和收缩。vector以连续的内存块存储元素,可以快速访问和修改任意位置的元素。 以下是vector的基本概念和特点: 动…...
微信、支付宝修改步数【小米运动】
简介 小米运动是一款流行的健身应用,可以记录用户的步数和运动数据。然而,有些用户希望能够修改步数,以达到一些特定的目的。本文将介绍一个Python脚本,可以帮助用户实现修改小米运动步数的功能。 正文 脚本介绍: 本脚本是一个Python脚本,用于修改小米运动步数。通过模…...
stu02-初识HTML
1.HTML概述 (1)HTML是Hyper Text Mark-up Language的首字母缩写。 (2)HTML是一种超文本标记语言。 (3) 超文本:指除了文字外,页面内还可以包含图片、链接、甚至音乐、视频等非文字元…...
软件测试7大误区
随着软件测试对提高软件质量重要性的不断提高,软件测试也不断受到重视。但是,国内软件测试过程的不规范,重视开发和轻视测试的现象依旧存在。因此,对于软件测试的重要性、测试方法和测试过程等方面都存在很多不恰当的认识…...
【深度学习】 Python 和 NumPy 系列教程(十二):NumPy详解:4、数组广播;5、排序操作
目录 一、前言 二、实验环境 三、NumPy 0、多维数组对象(ndarray) 多维数组的属性 1、创建数组 2、数组操作 3、数组数学 4、数组广播 5、排序操作 1. np.sort() 函数 2. np.argsort() 函数 3. ndarray.sort() 方法 4. 按列或行排序 5. n…...
CSS宽度问题
一、魔法 为 DOM 设置宽度有哪些方式呢?最常用的是配置width属性,width属性在配置时,也有多种方式: widthmin-widthmax-width 通常当配置了 width 时,不会再配置min-width max-width,如果将这三者混合使…...
浅谈C++|STL之string篇
一.string的基本概念 本质 string是C风格的字符串,而string本质是一个字符串 string和char * 区别 char * 是一个指针string是一个类,类内部封装了char *,管理这个字符串,是一个char * 型容器。 特点 string类内部封装了很多成…...
Kubernetes Dashboard安装部署
Kubernetes Dashboard安装部署 1. 下载Dashboard 部署文件2. 修改yaml配置文件3. 应用安装,查看pod和svc4. 创建dashboard服务账户5. 创建admin-user用户的登录密钥6. 登录6.1 使用token登录(1) 短期token(2) token长期有效 6.2 使用 Kubeconfig 文件登录 7.安装met…...
在Qt的点云显示窗口中添加坐标轴C++
通过摸索整理了三个方法: 一、方法1://不推荐,但可以参考 1、通过pcl的compute3DCentroid()方法计算点云的中心点坐标; 函数原型如下: compute3DCentroid (const pcl::PointCloud<PointT> &cloud, Eigen…...
[密码学入门]凯撒密码(Caesar Cipher)
密码体质五元组:P,C,K,E,D P,plaintext,明文空间 C,ciphertext,密文空间 K,key,密钥空间 E,encrypt,加密算法 D,decrypt,解密算法 单表代换…...
uboot 顶层Makefile-make xxx_deconfig过程说明三
一. uboot 的 make xxx_deconfig配置 本文接上一篇文章的内容。地址如下:uboot 顶层Makefile-make xxx_deconfig过程说明二_凌肖战的博客-CSDN博客 本文继续来学习 uboot 源码在执行 make xxx_deconfig 这个配置过程中,顶层 Makefile有关的执行思路。 …...
c++中的多线程通信
信息传递 #include <iostream> #include <thread> #include <chrono> #include <mutex> #include <condition_variable> #include <queue> // 用于存储和同步数据的结构 struct Data {std::queue<std::string> messag…...
IO day7
1->x.mind 2-> A进程 B进程...
C语言之指针进阶篇(3)
目录 思维导图 回调函数 案例1—计算器 案例2—qsort函数 关于qsort函数 演示qsort函数的使用 案例3—冒泡排序 整型数据冒泡排序 回调函数搞定各类型冒泡排序 cmp_int比较大小 cmp传参数 NO1. NO2. 解决方案 交换swap 总代码 今天我们学习指针难点之回调函数…...
SQL7 查找年龄大于24岁的用户信息
描述 题目:现在运营想要针对24岁以上的用户开展分析,请你取出满足条件的设备ID、性别、年龄、学校。 用户信息表:user_profile iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543female20…...
vite搭建vue3项目
参考视频 1.使用npm搭建vite项目,会自动搭建vue3项目 npm create vitelatest yarn create vite2.手动搭建vue3项目 创建一个项目名称的文件夹执行命令:npm init -y 快速的创建一个默认的包信息安装vite: npm i vite -D -D开发环境的依赖 安装vue,现在默认是vue3.…...
Qt中表格属性相关操作,调整表格宽度高度自适应内容等
1 表格列宽设置 利用Qt designer设计,可以通过改变表头的列宽从而保证内容不会被遮盖,输入空格的方式增加表头的长度,比如表头为"Value",则改成"Value ",可以扩展列默认的宽度,保证后面…...
NLP机器翻译全景:从基本原理到技术实战全解析
目录 一、机器翻译简介1. 什么是机器翻译 (MT)?2. 源语言和目标语言3. 翻译模型4. 上下文的重要性 二、基于规则的机器翻译 (RBMT)1. 规则的制定2. 词典和词汇选择3. 限制与挑战4. PyTorch实现 三、基于统计的机器翻译 (SMT)1. 数据驱动2. 短语对齐3. 评分和选择4. PyTorch实现…...
docker四种网络模式
文章目录 一.为什么要了解docker网络二.docker 网络理论三.docker的四类网络模式3.1 bridge模式3.2 host模式3.3 container模式3.4 none模式 四.bridge模式下容器的通信4.1 防火墙开启状态4.2 防火墙关闭状态 一.为什么要了解docker网络 当你开始大规模使用Docker时࿰…...
C 风格文件输入/输出---无格式输入/输出---(std::fgetc,std::getc,std::fgets)
C 标准库的 C I/O 子集实现 C 风格流输入/输出操作。 <cstdio> 头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数,而 <cwchar>头文件提供有宽字符输入/输出能力的函数。 无格式输入/输出 从文件流获取字符 std::fgetc, std::getc …...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
