C++ 动态数组 vector

动态数组

动态数组是一项运用十分广泛的技术,有助于解决大量不能预先确定数据量的问题。在 C++ 中,基础的动态数组可以使用 new 关键字开辟一片连续的内存空间充当数组。不过以这种方式开辟的数组使用起来比较僵硬,但是,C++ 为我们提供了功能强大的动态数组—— vector 类。

vector 简介

vector 是封装动态数组的容器。元素被连续存储,且用于存储的内存是自动管理的,按需扩张收缩。同时,vector 作为模板类,对存储的元素类型有着极高的灵活性。
vector 上的常见操作复杂度(效率)如下:
随机访问——𝓞(n)。
在末尾插入或移除元素——均摊常数 𝓞(1)。
插入或移除元素——与到 vector 结尾的距离成线性 𝓞(n)。
总而言之,vector 作为 C++ 提供的动态数组,使用它通常会占用多于静态数组的空间。但是其强大的功能性足以让人忽视这些缺点。

使用 vector

导入 vector 库

vector 在标头 < vector > 中定义为:

// C++ 17 之前的定义
template<
    class T,
    class Allocator = std::allocator<T>
> class vector;
// C++ 17 之后的定义
namespace pmr {
    template< class T >
    using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>;
}

使用时要加入头文件 < vector >,同时,作为标准库,使用时还要使用名称空间 std。

// 头文件
#include <vector>
// 使用名称空间 std
using namespace std;
// 或者
using std::vector;

创建 vector 容器

vector 容器的创建依赖其的构造函数,下面用 int 类型举例,介绍几个常用的构造函数:

  1. 默认构造函数。构造拥有默认构造的分配器的空容器。
// 函数声明原型为:vector();
vector<int> arr;
  1. 构造拥有 count 个值 value 的元素的容器。
// 函数声明原型为:vector( size_type count, const T& value = T());
vector<int> arr(5461, 0)
// 如果不填入第二个参数,值 value 将使用默认值
  1. 复制构造函数。构造拥有 other 内容副本的容器。
// 函数声明原型为:vector( const vector& other );
vector<int> arr_1(78);
vector<int> arr_2(arr_1);

元素访问

  1. 带越界检查访问指定的元素。
vector<int> arr(78);
// 函数声明原型为:reference at( size_type pos );
// 返回位于指定位置 pos 的元素的引用(从 0 开始计数),有边界检查。
// 若 pos 不在容器范围内,则抛出 std::out_of_range 类型的异常。
arr.at(50);
  1. 访问指定的元素(无越界检查)。
vector<int> arr(78);
// 函数声明原型为:reference operator[]( size_type pos );
// 返回位于指定位置 pos 的元素的引用。不进行边界检查。
arr[13];
  1. 访问第一个元素。
vector<int> arr(78);
// 函数声明原型为:reference front();
// 返回到容器首元素的引用。
// 注意:在空容器上调用 front 将导致出现未定义行为(未知风险)!
arr.front();
  1. 访问最后一个元素。
vector<int> arr(78);
// 函数声明原型为:reference back();
// 返回到容器中最后一个元素的引用。
// 注意:在空容器上调用 back 将导致出现未定义行为(未知风险)!
arr.back();

遍历容器

遍历 vector 容器有三种方式:下标遍历,迭代器遍历,范围 for 循环遍历。

下标遍历

由于数组下标与数组元素一一对应,所以,通过控制下标的值,即可完成对 vector 的遍历。
下面是使用示例:

vector<int> arr(78);
// 正向遍历
for (size_t i = 0; i < arr.size(); ++i)
{
	// 内部循环体代码(省略)
}

// 反向遍历
for (long long i = arr.size() - 1; i >= 0; --i)
{
	// 内部循环体代码(省略)
}

迭代器遍历

C++ vector 类为我们提供了迭代器,我们可以借助它方便快捷的完成对vector 容器的遍历。
下面是几个常用的迭代器和使用示例:

vector<int> arr(78);
// 函数声明原型为:const_iterator begin() const;
// 返回指向 vector 首元素的迭代器。
// 如果 vector 为空,那么返回的迭代器等于 end()。
arr.begin();

// 函数声明原型为:const_iterator end() const; 
// 返回指向 vector 末元素后一元素的迭代器。
// 注意:此元素为占位符;不要试图访问它!
arr.end();

// 函数声明原型为:const_reverse_iterator rbegin() const;
// 返回指向逆向的 vector 的首元素的逆向迭代器。它对应非逆向 vector 的末元素。
// 如果 vector 为空,那么返回的迭代器等于 rend()。
arr.rbigin()

// 函数声明原型为:const_reverse_iterator rend() const;
// 返回指向逆向的 vector 末元素后一元素的逆向迭代器。它对应非逆向 vector 首元素的前一元素。
// 注意:此元素表现为占位符,不要试图访问它!
arr.rend()// 正向遍历
for (auto it = arr.begin(); it != arr.end(); ++it)
{
	// 内部循环体代码(省略)
}

// 反向遍历
for (auto it = arr.rbigin(); it != arr.rend(); ++it)
{
	// 内部循环体代码(省略)
}

范围 for 循环遍历

范围 for 循环可以方便快捷的遍历容器中的元素,这里不过多介绍,我们直接看使用示例:

vector<int> arr(78);
// 正向遍历
for (auto &it : arr)
{
	// 内部循环体代码(省略)
}
// 等价于
for (auto it = arr.begin(); it != arr.end(); ++it)
{
	// 内部循环体代码(省略)
}
// 其中,上式中的 it 等价于下式中的 *it

容器容量相关

  1. 检查容器是否为空
vector<int> arr(78);
// 函数声明原型为:bool empty() const;
// 检查容器是否无元素
arr.empty();
  1. 返回容器元素数量
vector<int> arr(78);
// 函数声明原型为:size_type size() const;
// 返回容器中的元素数
arr.size();

容器内容修改相关

插入元素

  1. 插入元素
vector<int> arr(78);
// 函数声明原型为:iterator insert( const_iterator pos, const T& value );
// 在 pos 前插入 value。(pos 是vector 的迭代器)
arr.insert(arr.begin(), 23);

// 函数声明原型为:iterator insert( const_iterator pos, size_type count, const T& value );
// 在 pos 前插入 value 的 count 个副本。(pos 是vector 的迭代器)
arr.insert(arr.begin() + 3, 16, 1);
  1. 原位构造元素
vector<int> arr(78);
// 使用方法大致与 insert 相同,函数原型略
// 效率在一般情况下优于 insert
arr.emplace(arr.begin(), 23);
  1. 将元素添加到容器末尾
vector<int> arr(78);
// 函数声明原型为:void push_back( const T& value );
// 追加给定元素 value 到容器尾。
arr.push_back(18);
  1. 在容器末尾原位构造元素
vector<int> arr(78);
// 添加新元素到容器尾。使用方法大致与 push_back 相同,函数原型略
// 效率在一般情况下优于 push_back
arr.emplace_back(18);

注意:上述所有插入操作均会导致插入前的迭代器失效!

清除元素

  1. 清除内容
vector<int> arr(78);
// 函数声明原型为:void clear();
// 从容器擦除所有元素。此调用后 size() 返回零。
// 使任何指代所含元素的引用、指针和迭代器失效。
// 保持 vector 的内存容量(物理空间占用)不变
arr.clear();
  1. 擦除元素
vector<int> arr(78);
// 函数声明原型为:iterator erase( iterator pos );
// 移除位于 pos 的元素。(pos 是vector 的迭代器)
// 注意:pos 不能等于 vector::end() 所指向的迭代器
arr.erase(arr.begin() + 9);

// 函数声明原型为:iterator erase( iterator first, iterator last );
// 移除范围 [first, last) 中的元素。(first, last 是 vector 的迭代器)
arr.erase(arr.begin(), arr.begin() + 78);

注意:上述所有操作均会导致操作前的迭代器失效!

参考资料

https://zh.cppreference.com/w/cpp/container/vector

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值