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

相关推荐
Misnice4 分钟前
Python 内置函数大全
开发语言·windows·python
美狐美颜SDK开放平台5 分钟前
直播APP集成美颜SDK,如何梳理第三方组件的数据权限?
开发语言·人工智能·深度学习·音视频·第三方美颜sdk
怪我冷i26 分钟前
Rust 核心语法与内存安全机制
开发语言·安全·rust
开开心心_Every1 小时前
免费压缩软件WinRAR无弹窗、广告干扰
java·开发语言·前端·spring·智能手机·word·winrar
syagain_zsx1 小时前
WebSocket 教程:websocketpp 写 echo 服务端
linux·网络·c++·websocket·网络协议·工具库
江沉晚呤时1 小时前
零依赖的代价与自由:我用 C# 自研了一套 Office 读写库
开发语言·c#
大陈子编程1 小时前
C++ CSP-J 与 CSP-S 题单:洛谷 140 题知识点全覆盖
c++
想做小南娘,发现自己是女生喵1 小时前
QT项目实战第一周(嵌入式)
开发语言·qt
学逆向的1 小时前
C 可变量参数
c语言·开发语言·网络安全
andyweike1 小时前
kotlin dsl library工程怎么配置
android·开发语言·kotlin