3.3 标准库类型 vector


博主介绍:爱打游戏的计算机专业学生

博主主页:夏驰和徐策

所属专栏:夏驰和徐策带你从零开始学C++


思维导图:

 

3.3 标准库类型vector

概念与特性:
  • vector: 一种标准库容器,用于存放同一类型的对象集合。
  • 索引访问: 每个存储在vector中的对象都有一个对应的索引,用于访问。
  • 容器: 由于vector存放其他对象,因此也被称为容器。
使用前提:
  • 头文件: 使用vector前需包含头文件<vector>
  • 命名空间声明: 常用using std::vector;以便简化代码。
类模板与实例化:
  • 类模板: vector是一个类模板,需对C++有深入理解才能自定义模板。
  • 实例化: 使用模板时,需指定编译器将类或函数实例化成何种类型。
示例:
  • 定义vector实例:
    • vector<int> ivec; // 存储int类型对象
    • vector<Sales_item> Sales_vec; // 存储Sales_item类型对象
    • vector<vector<string>> file; // 存储vector<string>类型对象
注意事项:
  • 类型规定: vector是模板而非类型。由vector生成的类型必须包含元素的类型,如vector<int>
  • 不支持引用: 由于引用不是对象,因此不能有包含引用的vector。
  • 嵌套vector: vector的元素也可以是其他vector,但早期C++标准和某些编译器可能需要在尖括号之间添加空格。
警告:
  • 对于元素为vector的vector(即嵌套vector),某些编译器可能需要老式的声明方式,如vector<vector<int> >

 

3.3.1 定义和初始化vector对象
基本定义和初始化方法:
  1. 空vector:

    • vector<T> v1; - 默认初始化,不含任何元素,类型为T。
  2. 拷贝初始化:

    • vector<T> v2(v1); - v2包含所有v1的元素副本。
    • vector<T> v2 = v1; - 等价于v2(v1),含有所有v1元素的副本。
  3. 数量和值初始化:

    • vector<T> v3(n, val); - 包含n个重复元素,每个值为val。
    • vector<T> v4(n); - 包含n个执行值初始化的对象。
  4. 列表初始化:

    • vector<T> v5{a, b, c...}; - 包含初始值个数的元素,每个被赋予相应的初始值。
    • vector<T> v5 = {a, b, c...}; - 等价于v5{a, b, c...}。
使用场景和注意事项:
  • 空vector的用途:虽然空vector无元素,但常用于运行时动态添加元素。
  • 类型一致性:拷贝给另一个vector时,两个vector的类型必须相同。
  • 列表初始化注意点
    • C++11引入,使用花括号{}
    • 例如:vector<string> articles = {"a", "an", "the"}; 包含三个字符串元素。
特殊情况与限制:
  • 初始元素值的列表:如果提供的是元素值列表,应使用花括号进行列表初始化。
  • 创建指定数量的元素:可使用元素数量和统一初始值初始化vector。
  • 值初始化:如果元素是内置类型,如int,则自动初始化为0。如果是类类型,如string,则由类默认初始化。
  • 特殊限制
    • 某些类可能要求显式提供初始值。
    • 仅提供元素数量时,使用直接初始化而非拷贝初始化。
列表初始化与元素数量的歧义:
  • 花括号与圆括号的区别:花括号尝试列表初始化,圆括号用于构造vector对象。
  • 示例
    • vector<int> v1(10); - 10个值为0的元素。
    • vector<int> v2{10}; - 1个值为10的元素。
    • vector<int> v3(10, 1); - 10个值为1的元素。
    • vector<int> v4{10, 1}; - 2个元素,值分别为10和1。

3.3.2 向vector对象中添加元素
常见情况和基本方法:
  • 直接初始化:适用于初始值已知且数量较少,或所有元素初始值相同的情况。
  • 动态添加:更常见的情况是元素数量和值未知,或者虽然已知但数量庞大且各不相同。
使用push_back成员函数:
  • 基本使用v2.push_back(i); 将整数i添加到v2的尾端。
  • 适用场景
    • 当无法提前知道元素数量。
    • 当元素值在运行时确定。
    • 当初始化过程繁琐或不确定。
实例:
  • 顺序添加固定范围元素

    vector<int> v2;
    for(int i = 0; i != 100; ++i)
        v2.push_back(i); // 向v2添加0到99
    
  • 实时读取数据添加到vector

    vector<string> text;
    string word;
    while(cin >> word) {
        text.push_back(word); // 将输入的word添加到text
    }
    
性能考虑:
  • 动态增长效率:C++标准要求vector能高效快速地动态增长。
  • 避免预设大小:预设大小可能导致性能降低,特别是元素值不同的情况。
编程假定和要求:
  • 循环准确性:确保添加元素的循环逻辑正确,特别是当循环可能改变vector容量时。
  • 避免在范围for循环内修改大小:范围for语句体内不应改变遍历序列的大小。

3.3.3 其他vector操作
基本操作及用途:
  1. 空判断:

    • v.empty(): 判断vector v 是否为空,为空返回真,否则假。
  2. 大小获取:

    • v.size(): 返回vector v 中元素的个数。
  3. 添加元素:

    • v.push_back(t): 向vector v 的尾端添加一个值为t的元素。
  4. 元素访问:

    • v[n]: 返回vector v 中第n个位置上元素的引用。
  5. 赋值操作:

    • v1 = v2: 用vector v2 中元素的拷贝替换v1中的元素。
    • v1 = {a, b, c...}: 用列表中元素的拷贝替换v1中的元素。
  6. 比较操作:

    • v1 == v2, v1 != v2: 比较两个vector是否相等或不等。
    • <, <=, >, >=: 按字典顺序比较两个vector。
访问元素和迭代:
  • 使用范围for语句(如for(auto i : v) {...})处理vector中所有元素,更安全且易于理解。
  • 当需要修改vector中元素时,控制变量应定义为引用类型,以直接影响原元素。
索引和安全性:
  • 计算vector内对象的索引时,确保下标在合法范围内,避免缓冲区溢出和未定义行为。
  • 不要使用下标添加新元素。ivec[ix] = ix;ivec为空时是错误的。正确的方法是使用push_back
  • 只能对确知已存在的元素执行下标操作,否则可能导致运行时错误。
注意事项:
  • 下标安全:访问不存在的元素会引发错误。编译器不会检查下标的合法性,需程序员自行保证。
  • 范围for与安全:使用范围for语句可以确保不会访问无效的下标,是处理vector元素的安全方式之一。

 

理解C++标准库中的Vector

C++标准库中的vector是一种序列容器,它封装了能够存储和动态管理对象数组的功能。作为最常用的动态数组,它提供了丰富的功能和灵活性,使得处理序列数据变得更加容易。本文将深入探讨vector的特性、用法、优缺点以及如何有效地使用它。

Vector的基本概念

在C++中,vector定义在<vector>头文件中,它是一个模板类,可以存储任何类型的对象。与普通数组相比,vector最大的优势在于它可以动态地调整大小。

#include <vector>

int main() {
    std::vector<int> vec; // 创建一个空的int类型的vector
}

常用操作

初始化

vector提供了多种初始化方式,包括使用初始值列表、复制另一个vector的内容,或者指定元素的数量和值。

std::vector<int> vec1; // 空vector
std::vector<int> vec2(4, 100); // 4个元素,每个都为100
std::vector<int> vec3(vec2.begin(), vec2.end()); // 复制vec2
std::vector<int> vec4 {1, 2, 3, 4, 5}; // 初始化列表

访问元素

可以使用[]运算符或者at()方法访问vector的元素。at()方法与[]不同,它在索引超出范围时会抛出一个异常。

std::vector<int> vec = {10, 20, 30, 40};
int first = vec[0]; // 第一个元素
int last = vec.at(vec.size() - 1); // 最后一个元素

修改元素

vector提供了push_back()pop_back()等方法来添加和移除元素。

std::vector<int> vec;
vec.push_back(10); // 添加一个元素到末尾
vec.pop_back(); // 移除最后一个元素

大小和容量

可以使用size()来获取vector中的元素数量,使用capacity()来获取它在不重新分配内存的情况下可以容纳的元素数量。

std::vector<int> vec = {1, 2, 3};
size_t count = vec.size(); // 元素数量
size_t capacity = vec.capacity(); // 容量

性能考量

动态增长

当新元素被添加到vector中,并且当前的存储空间不足以容纳它时,vector会自动分配一个更大的存储空间,并将所有元素复制到这个新空间中。这个过程叫做重新分配,可能是一个昂贵的操作。为了减少重新分配的次数,可以使用reserve()方法来预分配足够的空间。

访问效率

vector提供了快速的随机访问能力,访问任何元素的时间复杂度都是O(1)。但是,在vector的开始或中间插入或删除元素的效率较低,因为这可能涉及到移动大量的元素。

实用技巧

  • 预分配内存:如果你知道将要存储多少元素,使用reserve()预分配空间可以避免多次重新分配。
  • 使用范围for循环:C++11引入的范围for循环可以简化对vector的遍历。
  • 注意迭代器失效:在进行插入或删除操作后,现有的迭代器可能会失效。
  • 选择合适的数据结构:虽然vector非常灵活,但在某些特定情况下,其他容器如listdeque可能更合适。

 

 

 

 

 

 

 总结:

3.3.1 定义和初始化vector对象

重点:

  1. 理解各种初始化方式:掌握空vector的创建,拷贝初始化,列表初始化等多种vector初始化方法及其用途。
  2. size_type的使用:了解如何正确使用vector<T>::size_type来表示大小和索引。

难点:

  1. 列表初始化 vs. 元素数量初始化:区分使用花括号{}和圆括号()进行初始化的区别,以及如何选择。
  2. 理解类型一致性:了解在拷贝初始化中vector类型必须相同的规则。

易错点:

  1. 错误的初始化方式:混淆使用=初始化和使用括号初始化的场景,导致不正确的初始化。
  2. 忽略size_type:使用普通的int类型作为索引,而不是使用vector<T>::size_type,可能导致类型不匹配问题。
3.3.2 向vector对象中添加元素

重点:

  1. push_back方法:熟练使用push_back向vector动态添加元素。
  2. 理解动态增长的效率:知道vector的大小是动态增长的,理解其对程序性能的影响。

难点:

  1. 循环控制和逻辑:确保在使用循环向vector添加元素时循环控制逻辑正确无误,尤其是在可能改变vector容量的情况下。

易错点:

  1. 修改循环中的vector大小:在范围for循环中改变vector的大小,导致未定义行为。
  2. 预设vector大小的误解:错误地认为预设vector大小会提高性能,而忽略了动态增长的效率和实际用途。
3.3.3 其他vector操作

重点:

  1. 掌握常用操作:理解并记住empty, size, []等方法的使用和语义。
  2. 索引和迭代:正确使用索引访问元素和通过范围for循环迭代vector。

难点:

  1. 安全访问元素:理解并确保在使用下标访问vector元素时的安全性,特别是对新添加的元素进行操作。

易错点:

  1. 越界访问:尝试访问不存在的元素,特别是在未检查vector大小的情况下使用下标访问。
  2. 混淆下标和push_back:试图使用下标方式添加元素到vector,而不是使用push_back
  3. 忽视比较操作的前提:在对vector进行比较操作时忽略了元素类型必须支持相应的比较操作。

结语

vector是C++中极其重要的部分,理解并有效使用它对于编写高效和可靠的C++代码至关重要。通过本文的学习,希望你能更好地理解vector的工作原理和使用方法,从而在实际编程中更加得心应手。

                                                                                                                                                          

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值