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

C++的vector类

目录

简介

特点

接口

构造函数

迭代器函数

Capacity系列

element access系列

modifiers系列

定义在全局的重载函数

find

总结


简介

vector 是 C++ 标准模板库(Standard Template Library,简称 STL)中的一个模板类,用于表示可以改变大小的数组。它是一种动态数组,能够在运行时自动调整其大小以适应元素的添加和删除。以下是 vector 的一些主要特点和用法:

特点

  1. 动态大小vector 的长度可以根据需要动态地增长或收缩。
  2. 连续存储vector 中的所有元素都存储在连续的内存位置中,这使得通过索引访问元素非常快速。
  3. 类型安全vector 是模板类,因此可以存储任何类型的元素,同时保持类型安全。
  4. 迭代器支持vector 提供了迭代器,允许使用迭代器进行元素遍历。
  5. 内存管理vector 自动管理内存分配和释放,避免了手动内存管理的复杂性。

下面通过vector的接口函数来进行vector的讲解。

接口

这是vector提供的内置成员函数

构造函数

提供了缺省、迭代器构造等多种构造

1)缺省:

Constructs an empty container, with no elements.生成一个空白的vector容器,没有任何元素。

2)用n个value去初始化

Constructs a container with n elements. Each element is a copy of val.

int main()
{
    vector<int> arr(10, 0);

    for (auto ch : arr)
        cout << ch << endl;
    return 0;
}

我们用10个0去初始化vector,如下是运行结果。

3)拷贝构造

int main()
{
    vector<int> arr(10, 0);
    vector<int> arr2(arr);

    for (auto ch : arr2)
        cout << ch << endl;
    return 0;
}

借助arr去拷贝出arr2,打印的结果同上。

4)采用迭代器区间

主要借助begin和end函数

这样就是打印8个0。

迭代器函数

begin

迭代器函数的行为类似指针,但不等价于指针,在使用时可以类比指针理解。

end

需要注意的是end指向最后一个元素的下一个位置。而不是最后一个元素。

Return iterator to end

Returns an iterator pointing to the past-the-end character of the string.

下面是示例:

// string::begin/end
#include <iostream>
#include <string>int main ()
{std::string str ("Test string");for ( std::string::iterator it=str.begin(); it!=str.end(); ++it)std::cout << *it;std::cout << '\n';return 0;
}

由于行为类似指针所以可以采用*(解引用)操作符去访问it。当然,果如繁琐的类型可以用auto推理。

rbegin()、rend()

相当于rbegin函数返回的是倒数第一个。rend则返回第一个的索引。

由于迭代器行为类似指针,因此也支持进行数据的修改。需要注意的是,在迭代的过程中,仍用++迭代。

cbegin cend、 crbegin crend则是表示const修饰过的迭代器

若要求只读,则可以用cbegin。

Capacity系列

这一系列主要是与容量的调整有关的接口

size() max_size()分别用来调出当然容量(含多少元素)是多少,可以容纳的最大容量是多少。

resize

用来修正size的大小。同时用来预开辟空间。预开辟空间十分重要,可以避免多次异地扩容。

这样size从10变成了20.

capacity

capacity返回的是容量,而不是size,体现的是可用空间。

int main()
{vector<int> arr(10, 0);arr[0] = 1;arr[9] = 9;cout << arr.size() << endl;cout << arr.capacity() << endl;arr.resize(20);cout << arr.size() << endl;cout << arr.capacity();return 0;
}

empty

Test whether vector is empty.用来检测容器是否为空。

reserve

对capacity进行修改,用来预开辟空间和进行空间修正。一般来说只大不小。需要注意的是,reserve只能将capcacity进行修正,不能对size进行修改。因此reserve(10)之后,可能size仍然为0。此时访问下标可能会造成越界访问

对于string类而言开辟n,实际内部开辟了n + 1个空间,用来存放\0。


int main()
{vector<int> arr;arr.reserve(11);for (int i = 0; i < 11; i++){arr.push_back(i);cout << arr[i] << endl;}return 0;
}int main()
{vector<int> arr;arr.reserve(11);arr.resize(11);for (int i = 0; i < 11; i++){arr[i] = i;cout << arr[i] << endl;}return 0;
}

shrink_to_fit

调整到合适的capacity大小,一般用处不大。

element access系列

1)

支持解引用,有专门的读与写的重载函数。

2)at

也适用于访问成员,一般用出不多。给定下标,访问成员

3)front、back系列

一般用back用的比较多。front用arr[0]替代

data()函数

可以得到一个指向有效数据的指针。这个功能在C++11及以后的版本中可用。

以下是一个使用 data() 函数的例子:

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};// 使用 data() 函数获取指向 vector 数据的指针int* dataPtr = vec.data();// 通过指针访问 vector 的元素for (size_t i = 0; i < vec.size(); ++i) {std::cout << dataPtr[i] << ' ';}std::cout << std::endl;return 0;
}
在上面的代码中,vec.data() 返回了一个指向 vec 中第一个元素的指针。然后我们使用这个指针来遍历并打印 vector 中的所有元素。

data() 返回的指针在 vector 被重新分配内存(例如通过 resize, reserve 或添加元素使得 vector 需要更多内存)后可能变得无效。因此,在使用 data() 返回的指针时,应避免修改 vector 的大小。

modifiers系列

1)assign

重新分配内容及size,但不会修改capacity

Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly.

可以传入迭代器、或者正常传参。

2)push_back()

尾插

3)pop_back尾删

4)insert插入

用来在任意位置插入元素

需要注意的是,在插入的位置需要传入的是迭代器,而不是下标.

int main()
{
    vector<int> arr;
    arr.reserve(100);
    auto it = arr.begin();
    arr.insert(it, 5, 10);
    for (auto& ch : arr)
        cout << ch << endl;
    return 0;
}

5)erase

用来删除某个或者某一段位置的数据,需要传入迭代器

6)swap

swap不只能交换内容,还可以交换size、capacity等信息。

int main()
{vector<int> arr;vector<int> arr2;arr.resize(100);arr2.resize(200);cout << arr.size() << " " << arr2.size() << endl;cout << arr.capacity() << " " << arr2.capacity() << endl;arr.swap(arr2);cout << arr.size() << " " << arr2.size() << endl;cout << arr.capacity() << " " << arr2.capacity() << endl;return 0;
}

7)clear

用于清空数据,包括size、content但不会销毁capacity

int main()
{vector<int> arr;arr.resize(100);cout << arr.capacity()<<" ";cout << arr.size() <<  endl;arr.clear();cout << arr.capacity() << " ";cout << arr.size() << endl;return 0;
}

定义在全局的重载函数

拿<举例

在C++中,std::vector 的 operator< 用于比较两个 vector 容器的大小。比较的规则是从两个 vector 的第一个元素开始,依次比较对应位置的元素,直到找到一个元素对,这两个元素在它们各自的 vector 中有不同的比较结果。以下是 operator< 的工作原理:

  1. 比较两个 vector 的对应元素,使用元素类型的 < 运算符。
  2. 如果在某个索引位置上,lhs 的元素小于 rhs 的对应元素,则认为 lhs 小于 rhs
  3. 如果在某个索引位置上,lhs 的元素大于 rhs 的对应元素,则认为 lhs 大于 rhs
  4. 如果所有对应元素都相等,但 lhs 的长度小于 rhs 的长度,则认为 lhs 小于 rhs
  5. 如果所有对应元素都相等,且两个 vector 的长度也相等,则认为它们相等,operator< 将返回 false

对于包含小数的 vector,比较过程如下:

  • 首先比较两个小数的整数部分。
  • 如果整数部分相同,则比较小数部分的十分位。
  • 如果十分位也相同,则比较百分位,依此类推。

以下是一个简化的示例,说明如何实现比较两个包含小数的 vector

#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::lexicographical_compareint main() {std::vector<double> vec1 = {1.1, 2.2, 3.3};std::vector<double> vec2 = {1.1, 2.3, 3.3};// 使用 std::lexicographical_compare 比较两个 vectorbool result = std::lexicographical_compare(vec1.begin(), vec1.end(),vec2.begin(), vec2.end());if (result) {std::cout << "vec1 is less than vec2" << std::endl;} else {std::cout << "vec1 is not less than vec2" << std::endl;}return 0;
}

在上面的代码中,std::lexicographical_compare 函数按照字典顺序比较两个序列,如果第一个序列在字典顺序上小于第二个序列,则返回 true。对于小数,它会使用 < 运算符,该运算符已经按照整数部分和小数部分的大小顺序进行了比较。

对于自定义类型,你需要确保 < 运算符对于该类型是定义好的,以 std::vector 的 operator< 能够正确比较元素。

如果 < 运算符没有为你的自定义类型定义,你需要自己定义它

下面的官方的示例

比较的是元素对,而不是元素的多少。

SWAP

定义在全局之后,就需要传入两个vector<T>对象。

find

这是他的头文件。

Find value in range

Returns an iterator to the first element in the range [first,last) that compares equal to val. If no such element is found, the function returns last.

找不到,返回end - 1的索引,打印7

找得到,返回4在arr中的索引,打印4

总结

1. vector是表示可变大小数组的序列容器。
2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理
3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 搭建jenkins一键部署java项目
  • pandas中的concat函数:详尽指南
  • HTTP简单概述
  • QML中的Date将时间戳和指定格式时间互转
  • 人工智能与机器学习的相关介绍
  • 速盾:cdn防盗链
  • 【C++标准模版库】模拟实现vector+迭代器失效问题
  • Flume系列之:把flume配置写入到zookeeper节点
  • net 工控机 字节转换 字符,ToString 格式化
  • 前端HTML+CSS复习
  • AIGC平台创业启示录:从Airbnb的成功经验中汲取灵感
  • 反制攻击者-蚁剑低版本
  • 腾讯OCR签名算法
  • EDI是什么:EDI系统功能介绍
  • Depth Anything——强大的单目深度估计模型
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • Angular 4.x 动态创建组件
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • Docker 笔记(2):Dockerfile
  • exports和module.exports
  • HTTP 简介
  • js中forEach回调同异步问题
  • leetcode388. Longest Absolute File Path
  • leetcode46 Permutation 排列组合
  • Odoo domain写法及运用
  • passportjs 源码分析
  • springMvc学习笔记(2)
  • 对JS继承的一点思考
  • 机器学习 vs. 深度学习
  • 如何利用MongoDB打造TOP榜小程序
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 探索 JS 中的模块化
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • # linux 中使用 visudo 命令,怎么保存退出?
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (javascript)再说document.body.scrollTop的使用问题
  • (ZT)一个美国文科博士的YardLife
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (原)Matlab的svmtrain和svmclassify
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .naturalWidth 和naturalHeight属性,
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net mvc部分视图
  • .net6 webapi log4net完整配置使用流程
  • .NET命名规范和开发约定