vector的基本概念
vector是c++标准模板库(stl)中最重要且最常用的容器之一,它本质上是一个封装了动态数组的类模板,提供了一系列便捷的方法来操作和管理数组数据。作为序列式容器的一种,vector支持在尾部高效地添加或删除元素,同时保持元素的线性存储顺序。
vector的实现原理是基于动态数组,它在内部使用连续的内存空间来存储元素。当现有容量不足时,vector会自动重新分配更大的内存空间(通常是当前容量的2倍),并将原有元素复制到新的内存区域。这个特性使得vector具有以下特点:
- 随机访问效率高:通过下标运算符[]或at()方法可以在o(1)时间内访问任意元素
- 尾部操作高效:push_back()和pop_back()操作的时间复杂度为o(1)
- 插入删除效率低:在中间位置插入或删除元素需要移动后续元素,时间复杂度为o(n)
vector的典型使用场景包括:
- 需要频繁随机访问元素的场合
- 数据量变化不大或主要在尾部增删的场合
- 需要兼容c风格数组的场合
基本操作示例:
#include <vector> using namespace std; vector<int> v; // 创建空vector v.push_back(10); // 尾部添加元素 v.insert(v.begin(), 5); // 在头部插入元素 int val = v[0]; // 随机访问 v.pop_back(); // 删除尾部元素
vector还提供了许多有用的成员函数,如size()获取元素数量,capacity()获取当前容量,reserve()预分配内存等,这些函数使得vector比原始数组更安全、更易于使用。
与传统静态数组的比较
与传统的静态数组相比,vector具有以下显著优势:
动态扩容能力:
- 当元素数量超过当前容量时,vector会自动分配更大的内存空间(通常是当前容量的1.5-2倍)并将原有元素拷贝到新空间
- 扩容策略可以通过reserve()方法预先指定,减少频繁扩容带来的性能开销
- 示例:
vector<int> v; v.reserve(100);预先分配100个元素的空间
自动内存管理:
- 用户无需手动分配和释放内存,vector会在析构时自动释放所有内存
- 遵循raii(资源获取即初始化)原则,避免内存泄漏
- 示例:
{ vector<int> temp; /*...*/ }作用域结束时自动释放内存
丰富的成员函数:
- 提供了push_back()、pop_back()、insert()、erase()等方法来方便地增删元素
- 支持size()、capacity()、empty()等状态查询方法
- 提供front()、back()快速访问首尾元素的方法
随机访问支持:
- 通过[]运算符或at()方法可以像普通数组一样快速访问任意位置的元素
- 时间复杂度为o(1),与静态数组相同
- 示例:
v[10] = 42;或int x = v.at(5);
常用操作示例
#include <vector>
#include <iostream>
int main() {
// 创建vector
std::vector<int> numbers;
// 尾部添加元素
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
// 访问元素
std::cout << "第一个元素: " << numbers[0] << std::endl;
// 遍历元素
for(int num : numbers) {
std::cout << num << " ";
}
// 删除尾部元素
numbers.pop_back();
return 0;
}
实际应用场景
在实际应用中,vector常用于以下场景:
需要频繁在尾部添加/删除元素的场合:
- 日志记录系统
- 数据采集缓冲
- 动态生成的结果集存储
需要随机访问元素的场合:
- 图像像素处理
- 数学向量/矩阵运算
- 游戏对象管理
无法预先确定元素数量的情况:
- 读取未知长度的用户输入
- 解析动态数据文件
- 数据库查询结果存储
需要将数据作为参数传递给函数时:
- 避免数组退化为指针
- 保持完整的容器信息(size/capacity等)
- 示例:
void process(const std::vector<int>& data);
例如:
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums; // 创建一个空的int型vector
// 添加元素
nums.push_back(10);
nums.push_back(20);
nums.push_back(30);
// 访问元素
std::cout << "第一个元素:" << nums[0] << std::endl;
std::cout << "当前容量:" << nums.capacity() << std::endl;
// 遍历元素
for(auto num : nums) {
std::cout << num << " ";
}
return 0;
}
需要注意的是,虽然vector提供了诸多便利,但在中间位置插入/删除元素时效率较低(o(n)复杂度),这种情况下可以考虑使用list等其他容器。此外,频繁的扩容操作也可能带来性能开销,可以通过reserve()方法预先分配足够空间来优化。
基本特性
动态扩容机制
当vector的size达到capacity时,会自动进行扩容:
- 扩容策略:大多数实现采用1.5倍或2倍扩容策略(如vs通常1.5倍,g++通常2倍)
- 扩容过程:分配新内存→拷贝元素→释放旧内存
- 时间复杂度:均摊o(1),但单次扩容可能达到o(n)
vector<int> v;
for(int i=0; i<100; i++){
v.push_back(i); // 自动扩容约7-8次(取决于实现)
}
内存布局
- 连续存储:所有元素在内存中连续排列,与普通数组一致
- 随机访问:支持通过下标直接访问,效率与数组相同
- 迭代器:提供随机访问迭代器,支持各种stl算法
类型安全
通过模板实现,可存储任意类型:
vector<string> names; vector<pair<int,double>> measurements; vector<vector<int>> matrix; // 二维数组
常用操作详解
初始化方式
// 1. 默认构造
vector<int> v1;
// 2. 指定大小和初始值
vector<int> v2(10, 0); // 10个0
// 3. 通过迭代器范围初始化
int arr[] = {1,2,3};
vector<int> v3(arr, arr+3);
// 4. 列表初始化(c++11)
vector<int> v4 = {1,2,3};
// 5. 拷贝构造
vector<int> v5(v4);
元素添加
vector<int> v; // 尾部添加 v.push_back(10); v.push_back(20); // 高效构造(c++11) v.emplace_back(30); // 直接在容器内构造,避免拷贝 // 任意位置插入 v.insert(v.begin(), 5); // 头部插入 v.insert(v.begin()+1, 2, 8); // 插入2个8
元素访问
// 下标访问(不检查边界)
int a = v[0];
// 安全访问(检查边界)
try {
int b = v.at(100); // 抛出out_of_range异常
} catch(out_of_range& e) {
cerr << e.what() << endl;
}
// 迭代器访问
for(auto it = v.begin(); it != v.end(); ++it) {
cout << *it << " ";
}
// 反向迭代器
for(auto rit = v.rbegin(); rit != v.rend(); ++rit) {
cout << *rit << " ";
}
// c++11范围for
for(int num : v) {
cout << num << " ";
}
元素删除
// 删除末尾元素
v.pop_back();
// 删除指定位置
v.erase(v.begin());
// 删除范围
v.erase(v.begin(), v.begin()+2);
// 条件删除(c++11)
v.erase(remove_if(v.begin(), v.end(),
[](int x){return x%2==0;}), v.end());
// 清空容器
v.clear();
容量管理
// 当前元素数量
size_t count = v.size();
// 当前容量
size_t cap = v.capacity();
// 是否为空
if(v.empty()) {
cout << "vector is empty" << endl;
}
// 预分配空间(避免多次扩容)
v.reserve(100);
// 释放多余空间
v.shrink_to_fit();
// 调整大小
v.resize(50); // 不足补0,多余删除
v.resize(100, -1); // 不足补-1
性能优化建议
预分配空间:已知元素数量时先reserve,避免多次扩容
vector<int> v; v.reserve(1000); // 预先分配 for(int i=0; i<1000; i++) { v.push_back(i); // 不会触发扩容 }选择合适的添加方法:
- 优先使用emplace_back而非push_back(避免临时对象)
- 批量插入时使用insert范围版本
避免不必要的拷贝:
// 返回vector的函数 vector<int> getdata() { vector<int> data; // ...填充data return data; // 移动语义优化,无拷贝 }元素类型选择:
- 存储大型对象时考虑存储指针
- 频繁插入删除时考虑list或deque
典型应用场景
动态数组需求
// 读取未知数量的输入 vector<int> inputs; int num; while(cin >> num) { inputs.push_back(num); }实现栈结构
vector<int> stack; stack.push_back(1); // push int top = stack.back(); // top stack.pop_back(); // pop
矩阵运算
vector<vector<double>> matrix(m, vector<double>(n)); // 矩阵操作...
算法容器
vector<int> data = {5,3,8,1,9}; sort(data.begin(), data.end()); auto it = find(data.begin(), data.end(), 8);缓存数据
vector<cacheentry> cache; cache.reserve(max_cache_size);
与其他容器对比
| 特性 | vector | deque | list |
|---|---|---|---|
| 随机访问 | o(1) | o(1) | o(n) |
| 头部插入 | o(n) | o(1) | o(1) |
| 尾部插入 | o(1) | o(1) | o(1) |
| 中间插入 | o(n) | o(n) | o(1) |
| 内存连续性 | 是 | 部分 | 否 |
vector是c++标准模板库(stsl)中最基础也是最重要的序列容器,它通过类模板的方式实现了一个动态数组。与普通数组相比,vector具有自动内存管理的特性,能够根据元素数量的变化动态调整存储空间。
内存管理机制:
- 初始分配:vector在构造时通常会分配一个初始容量(具体实现可能不同,常见为0或一个小值)
- 扩容策略:当元素数量超过当前容量时,vector会进行扩容。标准没有规定具体扩容倍数,但主流实现(如gcc、msvc)通常采用2倍扩容策略
- 内存释放:除非调用shrink_to_fit(),否则vector通常不会自动缩小容量
内存管理示例:
std::vector<int> v; // 初始容量可能是0
v.reserve(100); // 预分配100个元素空间
for(int i=0; i<200; ++i) {
v.push_back(i); // 当超过100时自动扩容
}
性能特点与优化
时间复杂度分析:
- 随机访问:o(1) - 通过下标直接访问
- 尾部操作:
- push_back/pop_back:平均o(1)
- emplace_back:平均o(1)
- 中间操作:
- insert/erase:o(n),因为需要移动后续元素
- 查找:o(n)(无序情况下)
性能优化技巧:
- 预分配空间:使用reserve()可避免多次扩容
std::vector<item> items; items.reserve(1000); // 预分配空间避免多次扩容
- 使用emplace_back代替push_back:
items.emplace_back(arg1, arg2); // 直接在容器中构造对象
- 避免不必要的拷贝:
std::vector<std::string> getdata() {
std::vector<std::string> result;
// ...填充数据
return result; // 利用返回值优化(rvo)或移动语义
}
典型应用场景
- 数据缓存:需要快速随机访问的临时数据存储
- 矩阵运算:多维数组的实现基础
- 图形处理:像素缓冲区、顶点数据存储
- 网络通信:数据包缓冲区的实现
- 替代原始数组:更安全、更易用的动态数组替代方案
与其他容器的对比
| 特性 | vector | list | deque |
|---|---|---|---|
| 内存布局 | 连续 | 非连续 | 分段连续 |
| 随机访问 | o(1) | o(n) | o(1) |
| 中间插入/删除 | o(n) | o(1) | o(n) |
| 迭代器失效 | 扩容时全部失效 | 通常不失效 | 复杂情况可能失效 |
| 缓存友好度 | 高 | 低 | 中等 |
到此这篇关于c++动态数组vector的使用小结的文章就介绍到这了,更多相关c++动态数组vector内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论