C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ STL 容器

C++ STL Vector容器详解

作者:L_兔力

vector是C++ STL中最重要的容器之一,这篇文章给大家介绍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

会造成:

所以 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 区别

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

十三、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 中最重要的容器之一。

核心知识:

到此这篇关于C++ STL vector容器详解的文章就介绍到这了,更多相关C++ STL 容器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文