C++初阶 Vector
一.vector的定义
1.vector():无参构造

创建一个空的 vector。

里面没有任何元素。
2.vector(size_type n, const value_type& val = value_type())
构造并初始化 n 个元素

表示创建 5 个元素,每个元素都是 10。
输出:10 10 10 10 10
如果不写第二个参数

等价于

再例如

等价于创建 3 个空字符串:


表示当前类型的默认值
3.vector(const vector& x):
拷贝构造
用一个已有的 vector 创建另一个新的 vector

此时 v2 里面的数据和 v1 一样
也可以这样写

这也是拷贝构造。
注意:v1 和 v2 是两个独立的容器。修改其中一个,不会影响另一个。

此时:

4.vector(InputIterator first, InputIterator last):
迭代器区间构造
用一段区间来初始化 vector。

表示用 v1 从 begin() 到 end() 的区间构造 v2。
结果:1 2 3 4 5
重点:区间是左闭右开。

原数据:1 2 3 4 5
构造结果:2 3 4
因为:
begin() + 1 指向 2
begin() + 4 指向 5
不包含 5
二.vector iterator 的使用
begin():获取第一个元素的位置。
end():获取最后一个元素的下一个位置。
注意:end() 不是最后一个元素,它是最后一个元素后面的位置。

输出:1
这里 it 指向第一个元素,*it 表示取出当前位置的数据。
正向遍历

输出:1 2 3 4 5
rbegin():获取最后一个元素的位置。
rend():获取第一个元素前一个位置。
它们用于反向遍历

输出:5 4 3 2 1
三. vector 空间增长问题
1. size
当前数据个数

输出:3
size() 表示:当前实际存储的数据数量

2. capacity
当前容量大小
capacity 表示:当前底层空间最多能放多少元素


已经用了 3 个位置, 但底层其实开了 8 个位置。
vector 不能每插入一个元素就重新申请空间,
效率会炸,所以 vector 会提前多申请空间,留着以后继续插入,这就是 capacity 的意义。
vector 扩容机制

当插入第 5 个元素时:vector 会申请更大的空间(通常 2 倍),拷贝旧数据,释放旧空间。
3. empty
判断是否为空

输出: 1
4. resize

修改元素个数 size
情况1 :变小

结果:

后面的元素被删除
size 和 capacity

resize 缩小通常不会缩容。
情况2:变大

结果:

新增元素默认初始化
指定新增值

结果:

resize 的本质
resize 操作的是“元素数量”,不是容量。

执行:

结果:

5. reserve
改变 capacity

提前预留空间
reserve 只改 capacity,不会改 size。

输出:0
100
提前预留空间,不会频繁扩容,性能提升非常明显 。
四.vector 增删查改
1. push_back —— 尾插
作用:在 vector 尾部插入元素

结果:

vector 底层是顺序表。
尾插时:
如果空间够 → 直接放末尾
如果空间不够 → 扩容 → 拷贝旧数据 → 插入新数据
2. pop_back —— 尾删
作用:删除最后一个元素

结果:

注意:
pop_back():没有返回值,不能删除空 vector
错误:

本质其实只是size --,所以效率非常高
3. find —— 查找
find 不是 vector 成员函数
它属于:<algorithm>
使用时要包含头文件#include <algorithm>
用法:

作用:在区间中查找某个值

如果找到的话
返回对应位置迭代器
找不到就返回end()
4. insert —— 插入
作用:在 pos 之前插入 val


结果:

中间插入

结果:

本质
vector 是连续空间,中间插入时,后面的元素都要后移。
5. erase —— 删除

作用:删除 pos 位置元素

结果:

删除区间

删除前两个元素
erase 返回值
返回:被删除位置的下一个迭代器
因为删除后,原迭代器失效了
经典错误:

因为erase 后 it 已失效
正确写法:

将下一个位置的迭代器再给it
6. swap —— 交换两个 vector

作用:交换两个 vector 的数据空间

结果:

本质:
不是逐个元素交换,而是直接交换内部指针,所以效率极高
7. operator[] —— 像数组一样访问

作用:访问第 i 个元素

输出: 2
修改元素

结果:

注意:[] 不检查越界。

可能直接崩溃。
五.vector 迭代器失效问题。
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
1.会引起其底层空间改变的操作,都有可能是迭代器失效

假设:

当前:

现在:

空间不够,vector 会:
申请新空间,拷贝旧数据,释放旧空间
原迭代器it原本指向旧空间,但旧空间已经没了。
于是:迭代器失效
push_back,insert,resize,reserve都可能引发迭代器失效
2.指定位置元素的删除操作
删除前:


vector 会后面元素整体前移
结果:

原来指向 30 的迭代器,现在位置已经变化
所以删除位置后的迭代器失效
3. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
现在:

执行:

如果空间不够string 会:
申请新空间,拷贝数据,释放旧空间
原迭代器it原本指向旧内存,但旧空间释放了
于是失效
4.解决迭代器失效的方法
在使用前,对迭代器重新赋值即可
erase

insert / push_back / reserve / resize 可能扩容,操作后重新获取迭代器。

提前 reserve,减少扩容导致的失效。

reserve 只能减少扩容风险,不能解决 insert / erase 导致元素移动的问题。
最标准写法就是

它的含义是:删除当前位置,并让 it 指向下一个有效位置。
更多推荐





所有评论(0)