Skip to content

vector容器详解

vector(动态数组)是STL中最常用的序列式容器,底层基于连续的内存空间实现,支持随机访问,可动态调整大小,兼顾了数组的高效访问和链表的灵活扩容,是日常开发和算法题中使用频率最高的容器之一,与关联式容器(set、map)形成互补。

一、vector核心特性

  1. 存储结构:连续内存空间,与普通数组类似,但支持动态扩容(自动分配更大的内存,拷贝原有数据);
  2. 访问效率:支持随机访问(通过下标访问),时间复杂度O(1),远高于list、set等容器;
  3. 插入删除:尾部插入/删除效率极高(O(1)),中间插入/删除效率较低(需移动后续元素,O(n));
  4. 灵活性:可动态调整大小,无需手动管理内存,支持各种算法(排序、查找等)。

vector与set、map的核心区别:vector是「序列式容器」,按插入顺序存储,不自动去重、不排序;set、map是「关联式容器」,按关键字存储,支持去重、排序和快速查找。

二、vector基础用法(完整代码)

cpp
#include <iostream>
#include <vector>  // vector的头文件
#include <algorithm>  // 用于排序等算法
using namespace std;

int main() {
    // 1. 定义vector(多种方式)
    vector<int> v1;  // 空vector,默认初始容量
    vector<int> v2(5, 0);  // 容量为5,所有元素初始化为0
    vector<int> v3(v2.begin(), v2.end());  // 拷贝v2的所有元素
    vector<int> v4 = {1, 2, 3, 4, 5};  // 初始化列表(C++11及以上)
    
    // 2. 插入元素
    v1.push_back(1);  // 尾部插入(推荐,效率高)
    v1.push_back(2);
    v1.insert(v1.begin() + 1, 3);  // 中间插入(在索引1的位置插入3)
    // 此时v1:[1, 3, 2]
    
    // 3. 访问元素(三种方式)
    cout << "通过下标访问v1[1]:" << v1[1] << endl;  // 输出:3(无越界检查)
    cout << "通过at访问v1[2]:" << v1.at(2) << endl;  // 输出:2(有越界检查,越界抛异常)
    cout << "通过迭代器访问:";
    for (auto it = v1.begin(); it != v1.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;  // 输出:1 3 2
    
    // 4. 修改元素
    v1[0] = 10;  // 下标修改
    v1.at(2) = 20;  // at修改
    // 此时v1:[10, 3, 20]
    
    // 5. 删除元素
    v1.pop_back();  // 尾部删除(效率高)
    v1.erase(v1.begin() + 1);  // 中间删除(删除索引1的元素)
    // 此时v1:[10]
    
    // 6. 常用操作
    cout << "\nvector大小(元素个数):" << v1.size() << endl;  // 输出:1
    cout << "vector容量(可存储元素个数):" << v1.capacity() << endl;  // 容量 >= 大小
    v1.resize(3, 0);  // 调整大小为3,新增元素初始化为0(此时v1:[10, 0, 0])
    if (v1.empty()) {
        cout << "vector为空" << endl;
    } else {
        cout << "vector非空" << endl;
    }
    
    // 7. 排序(需包含<algorithm>头文件)
    vector<int> v5 = {3, 1, 4, 1, 5};
    sort(v5.begin(), v5.end());  // 升序排序
    cout << "\n排序后v5:";
    for (auto x : v5) {
        cout << x << " ";
    }
    cout << endl;  // 输出:1 1 3 4 5
    
    // 8. 清空与释放内存
    v5.clear();  // 清空元素(大小变为0,容量不变)
    vector<int>().swap(v5);  // 释放多余容量(容量变为0)
    
    return 0;
}

三、vector的扩容机制

vector的底层是连续内存,当插入元素导致容量不足时,会自动扩容,扩容规则通常是:每次扩容为当前容量的2倍(不同编译器可能略有差异)。

扩容过程:

  1. 分配一块新的、容量为当前2倍的内存;
  2. 将原有内存中的所有元素拷贝到新内存;
  3. 释放原有内存;
  4. 将vector的指针指向新内存。

⚠️ 注意:频繁扩容会导致性能损耗(拷贝元素),若已知元素数量,可提前预留容量:

cpp
vector<int> v;
v.reserve(100);  // 提前预留100个元素的容量,避免频繁扩容

四、vector与set、map的对比(补充,帮助理解定位)

容器类型容器类别核心特点访问效率插入删除效率(中间)适用场景
vector序列式连续内存、随机访问、无去重O(1)(下标)O(n)频繁访问、尾部插入删除、需要排序
set关联式红黑树、值为key、去重、有序O(log n)O(log n)去重、有序查找、不需要key-value映射
map关联式红黑树、key-value映射、key唯一O(log n)O(log n)关键字映射、需要通过key查找value

五、常见误区与注意事项

  1. 下标访问越界:vector的[]操作符无越界检查,访问超出size的下标会导致未定义行为,建议用at()访问(有越界检查);
  2. 混淆size和capacity:size是当前元素个数,capacity是当前可存储的最大元素个数,size <= capacity;
  3. 中间插入删除效率低:vector中间插入/删除会移动后续所有元素,数据量较大时,建议用list(双向链表);
  4. 清空不释放内存:clear()仅清空元素(size=0),capacity不变,需用swap()释放多余容量;
  5. 迭代器失效:vector扩容后,原有迭代器会失效(指向原有内存),扩容后需重新获取迭代器。

六、适用场景总结

  1. 频繁通过下标访问元素(如:数组遍历、随机访问);
  2. 主要在尾部进行插入/删除操作(如:收集数据、拼接数组);
  3. 需要对元素进行排序、查找等算法操作(与algorithm配合使用);
  4. 数据量不大,或可提前预估数据量(避免频繁扩容)。

vector是STL中最基础、最常用的容器,与set、map、stack等容器配合使用,可覆盖绝大多数开发场景。

百炼成钢,融会贯通