目录
1、顺序容器(序列式容器,比如 vector、deque 等)
2、关联容器(关联式容器,比如 map、set、multimap、multiset 等)
四、vector 的增加删除都是怎么做的?为什么是 1.5 或者 2 倍?
一、vector 的扩容问题
1、为什么是两倍扩容?
下面这个博客很好的回答了该问题:
二、vector如何释放空间
由于 vector 的内存占用空间只增不减,比如你首先分配了 10,000 个字节,然后 erase 掉后面 9,999 个,留下一个有效元素,但是内存占用仍为 10,000 个。所有内存空间是在 vector 析构时候才能被系统回收。 empty() 用来检测容器是否为空的,clear() 可以清空所有元素。但是即使 clear() ,vector所占用的内存空间依然如故,无法保证内存的回收。
如果需要空间动态缩小,可以考虑使用 deque。如果 vector ,可以用 swap() 来帮助你释放内存。
vector(Vec).swap(Vec); // 将 Vec 的内存清除
vector().swap(Vec); // 清空 Vec 的内存
三、容器内部删除其中的元素,迭代器如何变化
1、顺序容器(序列式容器,比如 vector、deque 等)
erase 迭代器不仅使所指向被删除的迭代器失效,而且使被删除元素之后的所有迭代器失效(list 除外),所以不能使用 erase(it++) 的方式,但是 erase 的返回值是下一个有效迭代器。
It = c.erase(it);
2、关联容器(关联式容器,比如 map、set、multimap、multiset 等)
erase 迭代器只是被删除元素的迭代器失效,但是返回值是 void,所以要采用 erase(it++) 的方式删除迭代器。
c.erase(it++);
四、vector 的增加删除都是怎么做的?为什么是 1.5 或者 2 倍?
五、vector 的实现
vector 是一种序列式容器,其数据安排以及操作方式与 array 非常类似,两者的唯一差别就是对于空间运用的灵活性,众所周知, array 占用的是静态空间,一旦配置了就不可以改变大小,如果遇到空间不足的情况还要自行创建更大的空间,并手动将数据拷贝到新的空间中,再把原来的空间释放。 vector 则使用灵活的动态空间配置,维护一块连续的线性空间,在空间不足时,可以自动扩展空间容纳新元素,做到按需供给。其在扩充空间的过程中仍然需要经历:重新配置空间,移动数据,释放原空间 等操作。这里需要说明一下动态扩容的规则:以原大小的两倍配置另外一块较大的空间(或者旧长度 + 新增元素的个数),源码:
const size_type len = old_size + max(old_size, n);
vector 扩容倍数与平台有关,在 win + vs 下是 1.5倍,在 Linux + gcc 下是 2倍。
测试代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 在 Linux + gcc 下 是 2倍
vector<int> res(2, 0);
cout << res.capacity() << endl; // 2
res.push_back(1);
cout << res.capacity() << endl; // 4
res.push_back(2);
res.push_back(3);
cout << res.capacity() << endl; // 8
// 在 windows + vs2019 下 是 1.5倍
vector<int> res(2, 0);
cout << res.capacity() << endl; // 2
res.push_back(1);
cout << res.capacity() << endl; // 3
res.push_back(2);
res.push_back(3);
cout << res.capacity() << endl; // 6
return 0;
}
运行上述代码,一开始配置了一块长度为 2 的空间,接下来插入一个数据,长度变为原来的两倍,为 4 ,此时已占用的长度为 3,在继续两个数据,此时长度变为 8,可以清晰的看到空间的变化过程。
需要注意的是,频繁对 vector 调用 push_back() 对性能是有影响的,这是因为没插入一个元素,如果空间够用的话还能直接插入,若空间不够用,则需要重新配置空间,移动数据,释放空间等操作,对程序性能会造成一定的影响。