C++ vector使用方法

42.C++ vector使用方法——《跟老吕学C++》
C++ vector使用方法
一、什么是Vector?
二、容器特性
1. 顺序序列
2. 动态数组特性
3. 内存分配器感知(Allocator-aware)
三、基本函数实现
1. 构造函数
2. 增加函数
3. 删除函数
4. 遍历函数
5. 判断函数
6. 大小函数
7. 其他函数
8. 清晰说明
四、基本用法
五、简单介绍
六、vector使用实例
使用vector注意事项:
vector对象的定义和初始化
vector对象动态增长
1、基本操作
2、重要说明
3、算法
总结


C++ vector使用方法
在C++中,vector是一个功能强大的容器,它允许我们像使用容器一样来存储各种类型的对象。简单来说,vector是一个动态数组,能够存储任意类型的元素,并且支持数据的增加和删除操作。

C++中的传统数组有其局限性,那么是否有类似于Python中list的数据类型呢?答案是肯定的,那就是vector!vector是同一类型对象的集合,每个对象都对应一个整数索引值。与string对象类似,标准库负责管理与存储元素相关的内存。我们将vector称为容器,是因为它能够包含其他类型的对象。需要注意的是,一个vector容器中的所有对象都必须是同一种类型的。


一、什么是Vector?
Vector(向量)是一个顺序容器(Sequence Container),它封装了动态大小的数组。与其他类型的容器相似,Vector能够存储各种类型的对象。简而言之,Vector可以被视为一个可以容纳任意类型对象的动态数组。


二、容器特性
1. 顺序序列
容器中的元素遵循严格的线性顺序排列,用户可以根据元素在序列中的位置来访问特定的元素。

2. 动态数组特性
动态数组支持对序列中任意元素的快速直接访问,包括通过指针运算进行访问。此外,它还提供了在序列末尾相对高效地添加或删除元素的操作。

3. 内存分配器感知(Allocator-aware)
容器通过内存分配器对象来动态管理其存储需求,这使得容器能够更灵活、高效地进行内存的分配和释放。


三、基本函数实现
1. 构造函数
vector(): 创建一个空的vector。
vector(int nSize): 创建一个vector,其元素个数为nSize。
vector(int nSize, const T& t): 创建一个vector,其元素个数为nSize,且所有元素的值均为t。
vector(const vector& other): 复制构造函数,复制另一个vector。
vector(InputIterator first, InputIterator last): 使用迭代器first和last之间的元素来初始化vector。
2. 增加函数
void push_back(const T& x): 在向量的尾部增加一个元素x。
iterator insert(iterator it, const T& x): 在迭代器it指向的元素前增加一个元素x,并返回指向新插入元素的迭代器。
iterator insert(iterator it, size_t n, const T& x): 在迭代器it指向的元素前增加n个相同的元素x,并返回指向第一个新插入元素的迭代器。
iterator insert(iterator it, InputIterator first, InputIterator last): 在迭代器it指向的元素前插入另一个相同类型向量的[first, last)区间内的数据,并返回指向第一个新插入元素的迭代器。
3. 删除函数
iterator erase(iterator it): 删除迭代器it指向的元素,并返回指向下一个元素的迭代器。
iterator erase(iterator first, iterator last): 删除[first, last)区间内的元素,并返回指向下一个元素的迭代器。
void pop_back(): 删除向量的最后一个元素。
void clear(): 清空向量中的所有元素。
4. 遍历函数
reference at(size_t pos): 返回位置pos处元素的引用。
reference front(): 返回向量的第一个元素的引用。
reference back(): 返回向量的最后一个元素的引用。
iterator begin(): 返回指向向量第一个元素的迭代器。
iterator end(): 返回指向向量末尾之后位置的迭代器。
reverse_iterator rbegin(): 返回指向向量最后一个元素的反向迭代器。
reverse_iterator rend(): 返回指向向量第一个元素之前的反向迭代器。
5. 判断函数
bool empty() const: 判断向量是否为空,如果为空则返回true,否则返回false。
6. 大小函数
size_t size() const: 返回向量中元素的个数。
size_t capacity() const: 返回当前向量在不重新分配内存的情况下所能容纳的最大元素数。
size_t max_size() const: 返回vector能够容纳的最大元素数量值(通常是一个很大的值)。
7. 其他函数
void swap(vector& other): 交换两个同类型向量的数据。
void assign(size_t n, const T& x): 将向量的前n个元素设置为值x。
void assign(InputIterator first, InputIterator last): 用迭代器first和last之间的元素来替换向量的内容。
8. 清晰说明
push_back:在数组(或更准确地说是vector)的末尾添加一个数据项。
pop_back:移除vector的最后一个数据项。
at:根据编号位置获取数据项的值。
begin:返回指向vector第一个元素的迭代器(而非指针)。
end:返回指向vector尾后位置(即最后一个元素之后)的迭代器,表示vector的“结束”。
front:返回对vector中第一个元素的引用。
back:返回对vector中最后一个元素的引用。
max_size:返回vector理论上可以容纳的最大元素数量(通常非常大,实际限制取决于系统)。
capacity:返回当前vector已分配的空间大小,可以容纳的元素数量。
size:返回vector中当前实际存储的元素数量。
resize:改变vector的大小。如果新的大小大于当前大小,则用默认值填充新元素;如果小于当前大小,则删除多余元素。
reserve:改变vector的容量,即预分配存储空间的大小。
erase:删除指向的迭代器位置的元素或一系列元素。
clear:移除vector中的所有元素,使其变为空。
rbegin:返回指向vector最后一个元素的反向迭代器,即反转后的vector的开始。
rend:返回指向vector反转后尾后位置的反向迭代器,即反转后的vector的“结束”。
empty:检查vector是否为空,即是否不包含任何元素。
swap:与另一个vector交换其内容。

四、基本用法
在使用vector时,你需要包含相应的头文件,并可能使用std命名空间。以下是基本的包含和命名空间使用方式:

#include <vector>
using namespace std;
1
2

五、简单介绍
声明一个vector,并指定其元素的类型:
vector<类型> 标识符;
1
在声明vector的同时,可以指定其最大容量(但注意,vector是动态数组,其大小可以动态改变,这里的“最大容量”更多是一个初始预留空间的概念):
vector<类型> 标识符(最大容量);
1
在声明vector的同时,也可以指定其初始大小和所有元素的初始值:
vector<类型> 标识符(大小, 初始值);
1
如果你想从一个数组中获取一部分元素来初始化vector,可以使用以下方式(注意,数组名在C++中是指向第一个元素的指针):
int i[5] = {1, 2, 3, 4, 5};
vector<int> vi(i + 2, i + 5); // 得到i索引值为2到4的值(注意,C++中数组索引从0开始)
1
2
声明一个二维vector(即vector的vector):
vector<vector<int>> v; // 二维向量
// 注意:在声明二维vector时,最外层的尖括号<>之间不需要空格。但在某些旧的编译器中,可能需要空格来避免解析错误。
1
2

六、vector使用实例
使用vector注意事项:
当需要表示的向量长度较长(即需要为向量内部保存大量数据时),需要注意内存管理,避免潜在的内存泄漏问题,并且效率可能会受到影响。
当将vector作为函数的参数或返回值时,需要注意其传递方式。特别是在使用引用传递时,需要确保在函数内部正确地处理引用。
例如,定义一个计算两个整数向量之间距离的函数时,应如下写:

double Distance(const vector<int>& a, const vector<int>& b)
1
注意,这里使用了const关键字来确保向量的内容在函数内部不会被修改,并且虽然示例中省略了&的强调,但在实际编程中,如果不需要修改向量内容,使用const引用通常是一个好习惯。

vector对象的定义和初始化
在使用vector之前,需要包含相应的头文件,并可以使用using声明来简化代码。

#include <vector>
using std::vector;
1
2
vector是一个类模板(class template),它允许我们为多种不同的数据类型编写通用的类定义或函数定义。因此,我们可以定义保存string对象的vector,保存int值的vector,或者是保存自定义的类类型对象(如Sales_items对象)的vector。

在声明从类模板产生的某种类型的对象时,需要提供附加信息,即模板参数。对于vector,必须说明它保存的对象类型,通过将类型放在类模板名称后面的尖括号中来指定。

以下是几种vector对象的定义和初始化方式:

声明方式    描述
vector<T> v1;    声明一个保存类型为T的对象的vector。默认构造函数会创建一个空的vector。
vector<T> v2(v1);    声明一个保存类型为T的对象的vector,并将v2初始化为v1的一个副本。
vector<T> v3(n, i);    声明一个保存类型为T的对象的vector,并初始化v3包含n个值为i的元素。
vector<T> v4(n);    声明一个保存类型为T的对象的vector,并初始化v4含有n个值初始化的元素。
【注意】

若要创建非空的vector对象,可以使用带有元素数量和初始值的构造函数进行初始化。
当把一个vector对象复制到另一个vector对象时,新复制的vector中的每一个元素都会初始化为原vector中相应元素的副本。这两个vector对象必须保存同一种元素类型。
可以使用元素个数和元素值对vector对象进行初始化。构造函数使用元素个数来决定vector对象保存元素的个数,并使用元素值来指定每个元素的初始值。
vector对象动态增长
vector对象(以及其他标准库容器对象)的重要特性之一是其能够在运行时高效地添加元素。

注意:鉴于vector增长的高效率,当元素值已知时,最佳做法是动态地添加元素。

实例:

vector<int> test; // 创建一个vector,int为数组元素的数据类型,test为动态数组名
1
简单的使用方法如下:

vector<int> test; // 创建一个vector
test.push_back(1);
test.push_back(2); // 将1和2添加到vector中,这样test[0]就是1, test[1]就是2
1
2
3
实例(二维vector):

vector<vector<Point2f>> points; // 定义一个二维vector
// 注意:在访问points[0]之前,需要先确保points[0]已经被分配了内存
// points[0].size(); // 指第一行的列数(前提是points[0]已初始化)
1
2
3
1、基本操作
(1) 头文件包含:#include <vector>

(2) 创建vector对象:vector<int> vec;

(3) 尾部插入数字:vec.push_back(a);

(4) 使用下标访问元素:cout << vec[0] << endl;(记住下标是从0开始的)

(5) 使用迭代器访问元素:

vector<int>::iterator it;
for(it = vec.begin(); it != vec.end(); ++it)
    cout << *it << endl;
1
2
3
(6) 插入元素:vec.insert(vec.begin() + i, a); 在第i+1个位置插入a

(7) 删除元素:

* `vec.erase(vec.begin() + 2);` 删除第3个元素
* `vec.erase(vec.begin() + i, vec.begin() + j);` 删除区间[i, j-1](注意:结束迭代器是`vec.begin() + j`,不是`vec.end() + j`)
1
2
(8) 获取向量大小:vec.size();

(9) 清空:vec.clear();

特别提示:这里有begin()与end()函数、front()与back()的差别

2、重要说明
vector的元素不仅可以是int、double、string,还可以是结构体。但是要注意:如果结构体作为vector的元素,它应该被定义在全局作用域或类作用域内,以避免出现作用域问题。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Rect {
    int id;
    int length;
    int width;

    // 对于向量元素是结构体的,可在结构体内部定义比较函数
    bool operator<(const Rect &a) const {
        if (id != a.id)
            return id < a.id;
        else {
            if (length != a.length)
                return length < a.length;
            else
                return width < a.width;
        }
    }
};

int main() {
    vector<Rect> vec;
    Rect rect;
    rect.id = 1;
    rect.length = 2;
    rect.width = 3;
    vec.push_back(rect);
    vector<Rect>::iterator it = vec.begin();
    cout << it->id << ' ' << it->length << ' ' << it->width << endl;
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
3、算法
(1) 使用reverse翻转元素:需要头文件#include <algorithm>。

reverse(vec.begin(), vec.end()); // 将元素翻转,即逆序排列
1
(注意:在vector中,当使用需要两个迭代器的函数时,通常后一个迭代器指向的元素不包括在内。)

(2) 使用sort进行排序:需要头文件#include <algorithm>。

sort(vec.begin(), vec.end()); // 默认按升序排列,即从小到大
1
要按降序排列,可以定义比较函数并重写排序逻辑:

bool Comp(const int &a, const int &b)
{
    return a > b;
}

// 调用时
sort(vec.begin(), vec.end(), Comp); // 这样就实现了降序排序
1
2
3
4
5
6
7
输出vector中的元素

vector<float> vecClass;
int nSize = vecClass.size();

// 打印 vecClass, 方法一:
for (int i = 0; i < nSize; i++)
{
    cout << vecClass[i] << "\t";
}
cout << endl;

// 打印 vecClass, 方法二:
for (int i = 0; i < nSize; i++)
{
    cout << vecClass.at(i) << "\t";
}
cout << endl;

// 打印 vecClass, 方法三:
for (vector<float>::iterator it = vecClass.begin(); it != vecClass.end(); ++it)
{
    cout << *it << "\t";
}
cout << endl;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
需要注意的是:方法一和方法二都要求数组下标必须是整数。

二维数组的使用(但这里更推荐使用vector的嵌套来模拟二维数组)

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int out[3][2] = {{1, 2},
                     {3, 4},
                     {5, 6}};
    vector<int*> v1;
    for (int i = 0; i < 3; i++)
    {
        v1.push_back(out[i]);
    }
    cout << v1[0][0] << endl; // 1
    cout << v1[0][1] << endl; // 2
    // ... 以此类推
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
但请注意,直接使用原始二维数组和vector的int*类型混合可能会带来一些潜在问题,特别是当原始数组的生命周期结束时。更推荐的做法是使用vector<vector<int>>来模拟二维数组。


总结
std::vector是C++标准模板库中的一个非常有用的容器,它提供了动态数组的功能,并支持各种操作,如添加、删除、访问和遍历元素。通过正确使用vector,可以方便地处理动态数据集合。在使用vector时,需要注意其动态增长的特性以及可能带来的性能开销,并合理利用预留空间等优化手段来提高性能。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/molangmolang/article/details/140307118

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值