C++ vector 从入门到上手:核心基本用法全解析

C++ vector 从入门到上手:核心基本用法全解析

std::vector 是 C++ STL 中使用频率最高的容器之一,它是一个动态数组,可以自动扩容,几乎可以替代大部分手动管理的数组场景。

下面从零基础到能熟练使用,一次性把 vector 的核心用法讲清楚。

1. 引入 vector

#include <vector>      // 必须包含这个头文件
#include <iostream>
using namespace std;   // 方便演示(生产代码建议别全局 using)

2. 基本声明与初始化方式(最常用 6 种)

// 方式1:空 vector
vector<int> v1;

// 方式2:指定初始大小(元素默认初始化为 0)
vector<int> v2(10);          // 10 个 0

// 方式3:指定大小 + 初始值
vector<int> v3(10, 7);       // 10 个 7

// 方式4:用 initializer_list 初始化(C++11+ 最常用)
vector<int> v4 = {1, 2, 3, 4, 5};
vector<int> v5{10, 20, 30};   // 统一初始化语法

// 方式5:拷贝构造
vector<int> v6 = v4;          // 拷贝 v4
vector<int> v7(v4.begin(), v4.end());  // 范围构造

// 方式6:从数组构造
int arr[] = {100, 200, 300};
vector<int> v8(arr, arr + 3);
vector<int> v9(begin(arr), end(arr));   // C++11+ 更推荐

3. 常用成员函数速查表(背下来就够用)

功能写法时间复杂度说明 / 注意事项
元素个数v.size()O(1)当前元素数量
是否为空v.empty()O(1)size()==0 更语义化
容量v.capacity()O(1)已分配的内存空间(字节数 / sizeof(T))
访问(安全)v.at(i)O(1)越界抛出 out_of_range 异常
访问(不安全但快)v[i] / v.front() / v.back()O(1)不检查越界,生产代码慎用
添加元素(末尾)v.push_back(x)均摊 O(1)最常用,可能会触发扩容
移除末尾元素v.pop_back()O(1)不返回被删除元素
清空v.clear()O(n)size 变为 0,但 capacity 不变
插入(任意位置)v.insert(it, val)O(n)插入到迭代器 it 之前
删除(任意位置)v.erase(it)O(n)删除迭代器指向的元素,返回下一个有效迭代器
调整大小v.resize(n) / v.resize(n, val)O(n)变大时填充 val(默认 0),变小时截断
预分配空间v.reserve(n)O(n)提前分配空间,避免多次扩容
交换两个 vectorv1.swap(v2)O(1)极快,常用于清空 + 释放内存

4. 迭代器与遍历方式(C++11 之后最推荐)

vector<int> v = {10, 20, 30, 40, 50};

// 方式1:下标遍历(最直观)
for (size_t i = 0; i < v.size(); ++i) {
    cout << v[i] << " ";
}

// 方式2:迭代器遍历(传统写法)
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    cout << *it << " ";
}

// 方式3:C++11 范围 for(最推荐,简洁安全)
for (int x : v) {
    cout << x << " ";
}

// 方式4:C++17 结构化绑定(如果元素是 pair 等)
for (auto [key, value] : map_vec) { ... }

// 方式5:auto 自动推导(最常用写法)
for (auto x : v)           cout << x << " ";      // 拷贝
for (const auto& x : v)    cout << x << " ";      // 推荐(不拷贝)
for (auto& x : v)          x *= 2;                // 可修改原容器

5. 常用操作代码示例(直接复制可用)

#include <iostream>
#include <vector>
#include <algorithm>  // 用于 sort 等
using namespace std;

int main() {
    vector<int> v;

    // 1. 添加元素
    v.push_back(10);
    v.push_back(20);
    v.push_back(5);
    v.emplace_back(30);      // 比 push_back 更高效(原地构造)

    // 2. 遍历输出
    cout << "原始内容: ";
    for (const auto& x : v) cout << x << " ";
    cout << "\n";

    // 3. 插入
    v.insert(v.begin() + 1, 15);           // 在下标 1 位置插入 15

    // 4. 删除
    v.erase(v.begin());                    // 删除第一个元素

    // 5. 排序
    sort(v.begin(), v.end());

    // 6. 查找(需要 <algorithm>)
    auto it = find(v.begin(), v.end(), 20);
    if (it != v.end()) {
        cout << "找到 20 了!位置:" << (it - v.begin()) << endl;
    }

    // 7. 清空但保留容量
    v.clear();
    cout << "清空后 size = " << v.size() << ", capacity = " << v.capacity() << endl;

    // 8. 释放内存(当你真的不需要了)
    vector<int>().swap(v);   // 技巧:用空 vector 交换

    return 0;
}

6. 性能与注意事项(面试 + 生产必知)

  1. 扩容机制
    vector 容量不够时会重新分配更大的内存(通常 1.5~2 倍),然后把旧元素拷贝/移动过去
    → 导致均摊 O(1),但单次可能 O(n)
  2. reserve vs resize
  • reserve(n):只分配空间,不构造元素(推荐提前知道大概大小时使用)
  • resize(n):分配空间 + 构造元素(n > size 时填充默认值)
  1. 避免频繁插入/删除头部
    → O(n) 复杂度,考虑 std::dequestd::list
  2. emplace_back vs push_back
  • emplace_back 原地构造,效率更高(尤其元素是复杂对象时)
  1. 迭代器失效规则(非常重要!) 操作 迭代器是否失效 push_back(不触发扩容) 已有迭代器有效 push_back(触发扩容) 全部失效 insert / erase(中间) 插入/删除点之后的迭代器失效 pop_back 仅最后一个迭代器失效 clear / resize 全部失效 安全遍历删除写法
   for (auto it = v.begin(); it != v.end(); ) {
       if (*it % 2 == 0) {
           it = v.erase(it);   // erase 返回下一个有效迭代器
       } else {
           ++it;
       }
   }

7. 总结:vector 使用口诀

  • 小数据量、顺序访问、频繁尾部增删 → vector 是首选
  • 提前知道大概大小 → 先 reserve
  • 需要频繁插入删除 → 考虑 dequelist
  • 遍历优先用 for (const auto& x : v)
  • 删除时小心迭代器失效
  • 追求极致性能时用 emplace_back 而不是 push_back

如果你现在想练习哪一部分(比如 vector + 算法、vector 实现二维动态数组、vector 作为函数参数、常见面试题等),可以直接告诉我,我可以继续给出针对性的代码和讲解。

文章已创建 4547

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部