首页 > 编程语言 >C++(std::vector)

C++(std::vector)

时间:2024-09-07 11:52:06浏览次数:8  
标签:std 返回 元素 C++ vector 内存 向量

目录



std::vector 是 C++ 标准库中的一个动态数组容器,位于 #include <vector> 头文件中。它是一个模板类,可以存储任何类型的对象,并根据需要动态调整其大小。std::vector 提供了高效的随机访问、尾部插入/删除操作(O(1)),但在中间插入或删除元素的性能较差(O(n))。



1. 特性

  1. 动态大小std::vector 能自动调整大小,随着元素的增加,容量会自动扩展。
  2. 连续内存存储:由于 std::vector 的存储空间是连续的,它支持像数组一样的随机访问,时间复杂度为 O(1)。
  3. 自动管理内存std::vector 自动管理内存的分配和释放,不需要手动调用 newdelete
  4. 模板类:可以存储任意类型的对象,必须在创建 std::vector 时指定存储的对象类型,例如 std::vector<int> 存储整数,std::vector<std::string> 存储字符串。
  5. 支持范围检查:通过 at() 方法访问元素时会进行范围检查,如果索引越界会抛出 std::out_of_range 异常,而使用 operator[] 则不会进行检查。


2. 常用成员函数

2.1 构造函数

  • std::vector<T> v;:创建一个空的向量。
  • std::vector<T> v(n);:创建一个包含 n 个默认值为 T() 的元素的向量。
  • std::vector<T> v(n, value);:创建一个包含 n 个值为 value 的元素的向量。
  • std::vector<T> v{elements...};:通过初始化列表来初始化 std::vector

2.2 元素访问

  • v[i]:返回向量中第 i 个元素(不进行边界检查)。
  • v.at(i):返回向量中第 i 个元素(进行边界检查)。
  • v.front():返回第一个元素。
  • v.back():返回最后一个元素。
  • v.data():返回指向存储数组的指针。

2.3 修改容器

  • v.push_back(value):在向量的末尾添加元素 value
  • v.pop_back():删除向量中的最后一个元素。
  • v.insert(iterator, value):在指定位置插入元素。
  • v.erase(iterator):删除指定位置的元素。
  • v.clear():删除所有元素,使向量为空。
  • v.resize(n):调整向量大小为 n,若 n 大于当前大小,增加的元素将初始化为默认值。
  • v.reserve(n):预留空间至少能容纳 n 个元素,避免多次分配内存。

2.4 容量相关

  • v.size():返回向量中当前元素的数量。
  • v.capacity():返回向量当前容量,即不重新分配内存的情况下,最多能容纳多少元素。
  • v.empty():判断向量是否为空。

2.5 迭代器

  • v.begin():返回指向第一个元素的迭代器。
  • v.end():返回指向最后一个元素之后的迭代器。
  • v.rbegin():返回指向最后一个元素的反向迭代器。
  • v.rend():返回指向第一个元素之前的反向迭代器。


3. 内存管理与效率

  • std::vector 的内存分配具有一定的增长策略,当容量不足时,会重新分配一个更大的内存块(通常是当前容量的 1.5 倍或 2 倍),并将现有元素复制到新的内存块中。这种策略可以减少多次分配和复制的开销,但也可能导致暂时的内存浪费。

  • 使用 reserve() 可以预先分配足够的空间,从而避免多次扩容带来的开销,特别是在可以预测元素数量时。

  • shrink_to_fit():这个方法请求减少容量以匹配大小,不过实现可以选择忽略此请求。它可能会将未使用的空间释放给操作系统。



4. 示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    // 添加元素
    v.push_back(6);

    // 访问元素
    std::cout << "Element at index 2: " << v[2] << std::endl;
    std::cout << "First element: " << v.front() << std::endl;
    std::cout << "Last element: " << v.back() << std::endl;

    // 修改元素
    v[1] = 10;

    // 输出向量的所有元素
    for (int x : v) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    // 删除最后一个元素
    v.pop_back();

    // 输出当前大小和容量
    std::cout << "Size: " << v.size() << std::endl;
    std::cout << "Capacity: " << v.capacity() << std::endl;

    return 0;
}


5. 性能分析:

  • 时间复杂度:
    • 访问元素的时间复杂度为 O(1)。
    • 在尾部插入或删除元素的时间复杂度为摊销 O(1),因为扩展操作在多次插入后才会触发。
    • 插入或删除元素(非尾部)的时间复杂度为 O(n),因为插入或删除操作需要移动后续元素。
  • 内存重分配开销:扩展向量容量时会进行内存重分配,这时所有的元素会被复制到新的内存地址,因此在频繁插入大量元素时,提前使用 reserve() 可以提高效率。

std::vector 是 C++ 中最常用的容器之一,因其灵活的动态数组功能、优秀的性能和易用性而广受欢迎。尽管它的动态扩展会有一定的开销,但通过适当的预分配(使用 reserve())和合理的使用方式,std::vector 可以满足大多数应用场景中的性能需求。



标签:std,返回,元素,C++,vector,内存,向量
From: https://www.cnblogs.com/keye/p/18401509

相关文章

  • C++顺序结构(1)
    1、C++程序的样子2、流输出流COUT<<3、一个实例及解析//001程序的基本结构 //单行注释/*多行注释 被注释过的内容不会被运行,可以用来做笔记。基本结构:1.头文件 程序包含某个头文件后,程序中的代码就可以使用这个头文件里的功能。2.命名空间3.主函数 类似Scr......
  • C++:构造函数、析构函数
    目录一、类的默认成员函数二、构造函数构造函数的特点三、析构函数析构函数的特点一、类的默认成员函数    默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数,一个类,我们不写的情况下编译器会默认生成以下6个默认成员函数,默认成员函......
  • 南沙信C++陈老师解一本通题: 1101:不定方程求解
    ​ 【题目描述】给定正整数a,b,c。求不定方程 ax+by=c关于未知数x和y的所有非负整数解组数。【输入】一行,包含三个正整数a,b,c两个整数之间用单个空格隔开。每个数均不大于1000。【输出】一个整数,即不定方程的非负整数解组数。【输入样例】2318【输出样例】4......
  • C++ string类详解
    文章目录C++|string类详解1、标准库中的string类1.1string类介绍1.2auto关键字和范围for读写string1.2.1auto关键字1.2.2范围for组成内容:特点:举例:1.3string类的常用接口说明1.3.1常见构造方式1.3.2常见容量相关操作1.3.3string类对象的访问及遍历操作1.3.4stri......
  • C++vector类相关OJ练习
    个人主页:C++忠实粉丝欢迎点赞......
  • windows C++ 并行编程-转换使用取消的 OpenMP 循环以使用并发运行时
    某些并行循环不需要执行所有迭代。例如,搜索值的算法可以在找到值后终止。OpenMP不提供中断并行循环的机制。但是,可以使用布尔值或标志来启用循环迭代,以指示已找到解决方案。并发运行时提供允许一个任务取消其他尚未启动的任务的功能。此示例演示如何将一个不需要运行所有......
  • windows C++ 并行编程-使用 加速器 对象(下)
    并发运行时支持各种编程模型。这些模型可能会与其他库的模型重叠或对其进行补充。本部分中的文档将OpenMP与并发运行时进行比较,并提供有关如何迁移现有OpenMP代码以使用并发运行时的示例。OpenMP编程模型由开放标准定义,具有与Fortran和C/C++编程语言定义完善的绑定......
  • C++中的 new 与 delete
    我们今天来学习C++中的new与delete。它们2个是C++中的关键字,作用是在freestore(C语言中的堆区)中申请空间来存放数据。存在的意义为什么我们要在freestore中去存放数据呢?——因为freestore中的生命周期是由我们程序员所控制的。在某些时刻,我们只需要暂时性地使用一些数据。在这......
  • c++一个数因子和(快速求解)
    void一个数因子和(int整数){//缘由https://ask.csdn.net/questions/1054457#answer_1251715 inthe=0,j=0;stringa=""; while(++j<整数)if(!(整数%j))he+=j,a+=to_string(j)+"+"; cout<<a<<"的因子和:"<<he......
  • C++初学(19)
    19.1、文本IO如果你需要写入一千份以上的数据,如果手打那可太浪费时间了。这种情况下,应该让程序直接读取文件;同样的,让程序将输入写入到文件也是更加方便。文本I/O的概念:使用cin进行输入时,程序将输入视为一系列的字节,其中每个字节都被解释为字符编码。无论目标数据类型是什么,输......