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

相关推荐
别动我齐刘海14 分钟前
机器人运动控制学习2——基础进阶
c++·人工智能·神经网络·学习·目标检测·机器学习·机器人
小庞在加油18 分钟前
WinDbg实战:QT/跨平台项目死锁与无响应问题排查指南
开发语言·qt·windbg·工具
Vae_Mars1 小时前
C#中的delegate委托
开发语言·c#
傻啦嘿哟1 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
一直走下去-明1 小时前
简单的http抓包解包完整代码
开发语言·python
caimouse2 小时前
ReactOS 图形系统分析(51):元文件子系统 — metafile.c
c语言·开发语言
码匠许师傅2 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
闻道且行之2 小时前
图片处理助手|泊松融合原理 + C++ 工程实现,seamlessClone 三模式一次讲透
数据库·c++·人工智能·opencv
学习星球2 小时前
Solid.js 实战:拆解官方 RealWorld 项目
开发语言·javascript·vue.js
OPEN-F2 小时前
Python进阶教程:正则表达式进阶与文本处理
开发语言·python·正则表达式