C++ STL 容器详解:vector

一、vector 简介

1.1 什么是 vector?

vector 是 C++ STL(标准模板库)中的一种动态数组容器

它本质上是一块连续的动态内存空间,可以:

  • 自动扩容

  • 随机访问

  • 在尾部高效插入删除

  • 保存任意类型的数据

例如:

复制代码
#include <vector>

using namespace std;

int main()
{
    vector<int> v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    return 0;
}

此时:

复制代码
v
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
└───┴───┴───┘

vector 内部保存三个整数。


二、vector 的底层原理

理解 vector 最重要的是理解它的三个成员:

复制代码
start
finish
end_of_storage

可以理解为:

复制代码
        capacity空间

start                  end_of_storage
 ↓                          ↓
 ┌────┬────┬────┬────┬────┐
 │ 10 │ 20 │ 30 │    │    │
 └────┴────┴────┴────┴────┘
      ↑              ↑
   finish       可扩容空间

三个指针:

成员 作用
start 指向数组开始
finish 指向有效元素末尾
end_of_storage 指向申请空间末尾

size 和 capacity 区别

这是 vector 高频考点。

size()

表示:

当前已经存储多少个元素

例如:

复制代码
vector<int> v;

v.push_back(10);
v.push_back(20);

cout << v.size();

输出:

复制代码
2

capacity()

表示:

当前申请了多少内存空间

例如:

复制代码
vector<int> v;

v.push_back(10);

cout << v.capacity();

可能输出:

复制代码
1

也可能:

复制代码
2

因为不同编译器扩容策略不同。


例如:

复制代码
vector<int> v;

v.push_back(1);
v.push_back(2);
v.push_back(3);

可能:

复制代码
size = 3

capacity = 4

内存:

复制代码
capacity=4

┌───┬───┬───┬───┐
│ 1 │ 2 │ 3 │   │
└───┴───┴───┴───┘

三、vector 的初始化方式


3.1 默认初始化

复制代码
vector<int> v;

创建空 vector:

复制代码
size=0
capacity=0

3.2 指定大小

复制代码
vector<int> v(5);

创建 5 个元素:

复制代码
0 0 0 0 0

3.3 指定大小和值

复制代码
vector<int> v(5,10);

结果:

复制代码
10 10 10 10 10

3.4 使用数组初始化

复制代码
int arr[]={1,2,3,4};

vector<int> v(arr,arr+4);

结果:

复制代码
1 2 3 4

3.5 拷贝构造

复制代码
vector<int> v1{1,2,3};

vector<int> v2(v1);

两个 vector 独立:

复制代码
v1:
1 2 3


v2:
1 2 3

修改 v2:

复制代码
v2[0]=100;

不会影响 v1。

因为 vector 使用:

深拷贝


四、vector 常用接口大全


4.1 push_back()

尾插元素

复制代码
vector<int> v;

v.push_back(10);
v.push_back(20);

结果:

复制代码
10 20

时间复杂度:

复制代码
O(1)

平均情况下。


4.2 pop_back()

删除尾部元素

复制代码
v.pop_back();

例如:

复制代码
10 20 30

删除:

复制代码
10 20

注意:

只能删除最后一个。


4.3 size()

获取元素个数

复制代码
cout<<v.size();

返回:

复制代码
size_t

4.4 empty()

判断是否为空

复制代码
if(v.empty())
{
    cout<<"空";
}

返回:

复制代码
true / false

4.5 clear()

清空元素

复制代码
v.clear();

例如:

之前:

复制代码
1 2 3 4

之后:

复制代码

注意:

clear 不一定释放空间。

例如:

复制代码
vector<int> v(100);

v.clear();

cout<<v.capacity();

可能:

复制代码
100

4.6 reserve()

提前开空间

复制代码
vector<int> v;

v.reserve(100);

表示:

提前申请100个元素空间。

例如:

没有 reserve:

复制代码
1
2
4
8
16
32
...

不断扩容。

使用 reserve:

复制代码
capacity=100

减少扩容次数。


reserve 注意

复制代码
vector<int> v;

v.reserve(100);

cout<<v.size();

输出:

复制代码
0

因为:

reserve 只改变 capacity。

不会创建元素。


4.7 resize()

改变元素数量

例如:

复制代码
vector<int> v;

v.resize(5);

结果:

复制代码
0 0 0 0 0

指定值:

复制代码
v.resize(5,10);

结果:

复制代码
10 10 10 10 10

区别:

函数 作用
reserve 扩容空间
resize 改变元素数量

五、vector 的访问方式


5.1 operator\[\]

复制代码
vector<int> v={1,2,3};


cout<<v[0];

输出:

复制代码
1

特点:

不检查越界。

例如:

复制代码
v[10];

可能崩溃。


5.2 at()

复制代码
cout<<v.at(0);

特点:

检查越界。

例如:

复制代码
v.at(10);

抛异常:

复制代码
out_of_range

5.3 front()

访问第一个元素

复制代码
cout<<v.front();

5.4 back()

访问最后一个元素

复制代码
cout<<v.back();

六、vector 迭代器

迭代器是 STL 的核心。

vector 迭代器类似指针。


6.1 begin()

开始位置

复制代码
vector<int>::iterator it=v.begin();

指向:

复制代码
第一个元素

6.2 end()

结束位置

复制代码
v.end();

注意:

end 指向最后一个元素后面。

例如:

复制代码
1 2 3

^     ^
|     |
begin end

遍历 vector

方法1:普通 for

复制代码
for(size_t i=0;i<v.size();i++)
{
    cout<<v[i];
}

方法2:迭代器

复制代码
vector<int>::iterator it=v.begin();


while(it!=v.end())
{
    cout<<*it<<" ";
    it++;
}

方法3:范围 for

C++11:

复制代码
for(auto e:v)
{
    cout<<e;
}

七、vector 插入和删除


7.1 insert()

指定位置插入

例如:

复制代码
vector<int> v={1,2,3};


v.insert(v.begin()+1,100);

结果:

复制代码
1 100 2 3

时间复杂度:

复制代码
O(N)

因为需要移动元素。


7.2 erase()

删除指定位置

复制代码
v.erase(v.begin()+1);

例如:

复制代码
1 2 3

删除2:

复制代码
1 3

删除区间:

复制代码
v.erase(v.begin(),v.begin()+2);

删除:

复制代码
前两个元素

八、vector 扩容机制(重点)

当空间不足:

例如:

复制代码
capacity=3

1 2 3

继续:

复制代码
push_back(4);

发生:

  1. 申请更大的空间

  2. 拷贝旧数据

  3. 释放旧空间

  4. 插入新数据

过程:

复制代码
旧空间

1 2 3


↓

新空间

1 2 3 _ _ _


↓

释放旧空间

为什么 vector 扩容不是一点一点增加?

因为:

如果每次增加1:

插入n个元素:

需要大量搬迁。

效率:

复制代码
O(n²)

所以通常采用:

复制代码
2倍扩容

达到:

均摊 O(1)


九、vector 的深浅拷贝

vector 内部:

保存:

复制代码
指针
数据
容量

如果浅拷贝:

复制代码
v1

↓

同一块空间

↑

v2

会造成:

  • 修改互相影响

  • double free

所以 vector 使用:

深拷贝

例如:

复制代码
vector<int> v1={1,2,3};

vector<int> v2=v1;

内存:

复制代码
v1:

1 2 3


v2:

1 2 3

两个空间独立。


十、vector 失效问题(面试重点)

10.1 扩容导致迭代器失效

复制代码
vector<int> v={1,2,3};

auto it=v.begin();


v.push_back(4);


cout<<*it;

可能错误。

原因:

扩容后:

旧空间释放。

原 iterator 指向:

复制代码
已经释放的地址

10.2 erase导致迭代器失效

复制代码
auto it=v.begin();

v.erase(it);

之后:

it 不可使用。


十一、vector 与数组区别

数组 vector
大小 固定 动态
内存 栈区 堆区
扩容 不能 可以
效率 略低
安全性

十二、vector 与 list 区别

vector list
底层 连续数组 链表
随机访问
插入删除 中间慢
缓存友好

十三、vector 性能分析

操作 复杂度
随机访问 O(1)
尾插 O(1)
尾删 O(1)
头插 O(N)
中间插入 O(N)
查找 O(N)

十四、vector 模拟实现(核心思想)

简单版本:

复制代码
template<class T>
class Vector
{
public:

    Vector()
    {
        _start=nullptr;
        _finish=nullptr;
        _end=nullptr;
    }


private:

    T* _start;
    T* _finish;
    T* _end;

};

三个指针:

复制代码
_start

 ↓

[1][2][3][ ][ ]

       ↑
    finish

              ↑
          end

这就是 STL vector 的核心结构。


十五、vector 高频面试题

1.vector 为什么支持随机访问?

因为:

底层是连续数组。

可以:

复制代码
地址=首地址+下标*sizeof(type)

2.vector 为什么尾插效率高?

因为:

尾部空间直接写入。


3.vector 扩容为什么消耗大?

因为:

需要:

  • 申请新空间

  • 拷贝数据

  • 释放旧空间


4.reserve 和 resize区别?

答案:

复制代码
reserve:
改变容量

resize:
改变元素数量

5.vector 如何释放空间?

方法:

复制代码
vector<int>().swap(v);

原理:

创建临时空 vector

交换资源。


总结

vector 是 C++ STL 中最重要的容器之一。

核心知识:

  1. vector 是动态数组

  2. 底层是一块连续空间

  3. 使用三个指针管理数据

  4. size 表示元素数量

  5. capacity 表示容量

  6. 扩容会导致迭代器失效

  7. 尾插效率高

  8. 中间插入删除效率低

  9. 支持随机访问

  10. STL 中大量算法基于 vector

相关推荐
xiaoye-duck1 天前
《Linux系统编程》Linux 系统多线程(七): C++ 线程安全日志系统封装:基于策略模式解耦,兼容 glog 使用风格
linux·c++·日志系统
weixin_585951171 天前
CH592F 2.4G 低功耗
c语言·开发语言
秋田君1 天前
QT_QInputDialog类输入对话框
开发语言·qt
name好难取诶1 天前
通过对云基座和离线基座的对比,帮助开发者理解如何在不同场景下选择合适的打包方案。 什么是“基座” 在 UniApp 中,基座(也称“ ...
开发语言·uni-app·php
盒子里的加菲猫1 天前
什么?不会C语言也可以搭建窗口级应用程序?(Electron)
c语言·开发语言·electron
程序喵大人1 天前
【C++进阶】STL容器与迭代器 - 07 迭代器是容器和算法之间的通用游标
开发语言·c++·算法
汉克老师1 天前
GESP2026年3月认证C++七级( 第三部分编程题(1、拆分))精讲
c++·预处理·dp·取模·gesp7级·数学规律·对数
名字还没想好☜1 天前
Next.js App Router 约定式文件实战:loading、error、not-found 怎么兜住加载态与异常
开发语言·前端·javascript·react·next.js
BerryS3N1 天前
C++在AI时代的核心力量:从底层加速到大规模大模型推理引擎的高能实践
开发语言·c++·人工智能
AAIshangyanxiu1 天前
R 语言耦合遥感技术的水环境综合评估完整技术体系,水质水深水温定量反演方法
开发语言·r语言·遥感水文·水文遥感·r语言遥感