std::vector
一、vector简介
C++ 的 vector本质上是一个动态数组,它的元素是连续存储的,这意味着不仅可以通过迭代器访问元素,还可以使用指向元素的常规指针来对其进行访问。还可以将指向 vector 元素的指针传递给任何需要指向数组元素的指针的函数。
vector 的存储是自动处理的,可以根据需要进行扩展和收缩。vector通常比静态数组占用更多的空间,因为分配了更多的内存来处理将来的增长。这样,vector 不必在每次插入元素时都重新分配,而仅在附加内存耗尽时才需要重新分配。可以使用 capacity() 函数查询已分配的内存总量。可以通过调用 shrink_to_fit() 将额外的内存返回给系统。
就性能而言,重新分配空间通常是费时的操作。如果元素的数目是预先已知的,调用 reserve() 函数可以消除重新分配。
二、vector优缺点
- 优点:
- 可以不用指定vector的大小
- 随机访问方便(因为内存是连续的),即支持[]操作符和vector.at()
- 节省空间(vector在开始就创建适合的容量,防止自动扩充大小,节省内存,当插入的个数大于容量时,则容量自动扩充一倍)
- 缺点:
- 插入和删除效率低,复杂度高O(n)
- 当元素超出容量时,重新分配内存空间,扩充一倍。元素拷贝到新空间,释放原来的内存,原来的迭代器失效。
三、构造vector
std::vector<int> v0(3, 100); //3个100,即相当于v0 {100,100,100}
std::vector<int> v1 = { 1,2,3,4 }; //有无 = 都正确
四、增加元素
1. push_back:添加一个元素到容器尾部
void push_back (const value_type& val);
void push_back (value_type&& val);
2. insert:将一个或多个元素添加到一个指定位置
iterator insert(const_iterator position, const value_type & val);
iterator insert(const_iterator position, size_type n, const value_type & val);
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, value_type && val);
iterator insert(const_iterator position, initializer_list<value_type> il);
3. emplace_back:和push_back对应
template <class... Args>
void emplace_back (Args&&... args);
4. emplace:和insert对应
template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
5. emplace_back 和 push_back 的区别
push_back的过程
-
构造一个临时对象
-
调用移动构造函数把临时对象的副本拷贝到容器末尾增加的元素中
-
调用析构释放临时对象
emplace_back 的过程
- 调用构造函数在容器末尾增加一个元素
优缺点
emplace_back比push_back的效率更高,但是使用emplace_back的代码健壮性不如push_back,例如
点击查看代码
std::vector<int> vec1;
vec1.push_back(3);
vec1.emplace_back(5);
std::vector<std::vector<int>> vec2;
//vec2.push_back(3);// 报错
vec2.emplace_back(5); // vec2 = { {0,0,0,0,0} }
示例代码:
点击查看代码
std::vector<int> vec{ 1,2,3 };
std::vector<int>::iterator it;
vec.push_back(4); //1,2,3,4
vec.emplace_back(5); //1,2,3,4,5
it = vec.begin() + 1;
auto r1 = vec.emplace(it,6); //1,6,2,3,4,5 在vec的第一个位置加1(即第二个元素)之前添加一个元素
auto r2 = vec.insert(r1, 7); //1,7,6,2,,3,4,5 //注意此处不能再用it,因为it迭代器对应的vector已经发生了变化
std::vector<int> vec2{ 9,8,7 };
auto r3 = vec.insert(r2, vec2.begin(), vec2.end()-1); //1,9,8,7,6,2,3,4,5共9个元素,将vec2的9和8添加到vec的r2位置之前
auto r4 = vec.insert(r3, 3, 4); //1,4,4,4,9,8,7,6,2,3,4,5在vec的r3位置之前加入3个4
五、删除元素
1. erase:
iterator erase (const_iterator position); //删除指定的一个元素
iterator erase (const_iterator first, const_iterator last); //删除区间所有元素
删除一个值为value的元素需要用到std::find先查找到位置的迭代器然后再删除(如果vector中存在多个相同的值,std::find只会查找到第一个)。
vec.erase(std::find(vec.begin(),vec.end(),value));
2.erase_if (C++20):
template< class T, class Alloc, class Pred >
constexpr typename std::vector<T, Alloc>::size_type
erase_if(std::vector<T, Alloc>& c, Pred pred);
3. pop_back:
void pop_back(); //删除最后一个元素
4. clear:
void clear() noexcept; //清空所有元素
5.示例代码:
点击查看代码
std::vector<int> vec3 = { 1,2,3,4,5,6,7,8,9 };
vec3.erase(vec3.end()-2); //12345679 删除倒数第二个元素
vec3.erase(vec3.end()-3, vec3.end()); //12345 删除从倒数第三个元素开始,到最后一个元素之间的所有元素
vec3.pop_back(); //1234 删除最后一个元素
vec3.clear(); //相当于vec3.erase(vec3.begin(),vec3.end())
六、修改元素
1. swap:
void swap (vector& x); //交换两个容器的元素
2. assign:
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
void assign(size_type n, const value_type& val);
void assign(initializer_list<value_type> il);
3. 利用operator[]、at()以及find()修改元素
4. 示例代码:
点击查看代码
std::vector<std::string> vec4(3, "abc"); //abc,abc,abc
vec4[1] = "xyz"; //abc,xyz,abc
std::string str1("ooo");
vec4.at(0) = str1; //ooo,xyz,abc
vec4.front() = "front"; //front,xyz,abc
vec4.back() = "back"; //front,xyz,back
std::vector<int> vec5(5, 6); //666666
vec5.assign(3, 4); //444 以3个4替换vec5原来的所有元素
vec5.assign(v1.begin() + 1, v1.end()); //234 用v1第二个元素到最后一个元素替换vec5原来的所有元素
vec5.assign({ 9,9,9 }); //999 用3个9替换vec5原来的所有元素
std::vector<int> vecInt{ 1,2,3,4,5 };
auto it1 = find(vecInt.begin(), vecInt.end(), 3);
if(it1!=vecInt.end())
*it1 = 9; //vecInt = 1,2,9,4,5
七、查找元素
1. at:访问第n个元素(从0开始)
注意:访问越界会出现异常,所以谨慎使用
reference at (size_type n); //返回引用,可以利用此修改元素
const_reference at (size_type n) const;
2. [i]:访问第i个元素(从0开始)
注意:访问越界会出现异常
auto r6 = vec6[1]; //2
3. front:返回容器首元素的引用
reference front();
const_reference front() const;
4. back:返回容器末尾元素的引用
reference back();
const_reference back() const;
5. data:返回指向内存中数组第一个元素的指针(容器为空返回nullptr,不可以对该指针解引用)
value_type* data() noexcept;
const value_type* data() const noexcept;
6. find:返回指向首个满足条件的迭代器,或若找不到这种元素则为end()
std::find需要包含头文件<algorithm>
template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);
7. 示例代码:
点击查看代码
std::vector<int> vec6{ 1,2,3,4,5,6,5 };
auto r5 = vec6.at(0); //1
auto r6 = vec6[1]; //2
auto r7 = vec6.front();//1
auto r8 = vec6.back(); //5
std::vector<int> vec7;
auto r9 = vec7.data();
//auto r10 = *r9; //会出现异常
auto r11 = find(vec6.begin(), vec6.end(), 5); //返回指向5的迭代器,返回的是查找到的第一个迭代器
auto r12 = *(r11-1); //4
八、比较
非成员函数==
,两个vector所有元素都相等则返回true,不相等返回false,使用==
的前提是,两个vector的模板初始化参数一致。
九、大小和容量
1. 获取大小或容量
-
capacity():返回容量,即可以存放的元素个数。如果没有使用reserver()设置容量,就返回vector的元素个数
-
size():返回大小,即实际元素的个数
-
max_size():返回可容纳的最大元素个数,vs为:4611686018427387903
2. 设置大小或容量
- resize():设置容器的大小,如果设置之前的容量大于该大小,则容量不会变化,否则容量也变化为该大小。会修改size()和capacity()
void resize( size_type count, T value = T() ); //设置大小为count,且用count个value填充
- reserver():设置容器预留空间,(会涉及到内存的释放与申请,因为vector在一段连续的内存空间存储,如果容量大于原容量,且当前内存空间不足,就会重新申请内存空间并将原来的元素复制过去(拷贝构造),且释放掉原来的内存空间。不会修改容器的大小。只会修改capacity,不会修改size()
点击查看代码
vector<int> v1;
vector<int> v2;
vector<int> v3;
auto _capacity1 = v1.capacity(); //0
auto _size1 = v1.size(); //0
auto _max_size1 = v1.max_size(); //4611686018427387903
v1.resize(10);
auto _capacity2 = v1.capacity(); //10
auto _size2 = v1.size(); //10
auto _max_size2 = v1.max_size(); //4611686018427387903
v2.reserve(20);
auto _capacity21 = v2.capacity(); //20
auto _size21 = v2.size(); //0
auto _max_size21 = v2.max_size(); //4611686018427387903
v3.reserve(2);
v3.insert(v3.begin(), 3,5);
auto _capacity31 = v3.capacity(); //3
auto _size31 = v3.size(); //3
auto _max_size31 = v3.max_size(); //4611686018427387903
十、 vector转指针
例如:vector<int>转int*,注意:该指针离开当前作用域后将会失效。
int* p = vec.data();
十一、自己实现一个vector
待添加
十二、获取vector的最大值最小值
-
std::max_element
-
std::min_element
完整示例代码:
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
//构造
std::vector<int> v0(3, 100); //3个100,即相当于v0 {100,100,100}
std::vector<int> v1 = { 1,2,3,4 }; //有无 = 都正确
//增加
std::vector<int> vec1{ 1,2,3 };
std::vector<int>::iterator it;
vec1.push_back(4); //1,2,3,4
vec1.emplace_back(5); //1,2,3,4,5
it = vec1.begin() + 1;
auto r1 = vec1.emplace(it, 6); //1,6,2,3,4,5 在vec1的第一个位置加1(即第二个元素)之前添加一个元素
auto r2 = vec1.insert(r1, 7); //1,7,6,2,,3,4,5 //注意此处不能再用it,因为it迭代器对应的vector已经发生了变化
std::vector<int> vec2{ 9,8,7 };
auto r3 = vec1.insert(r2, vec2.begin(), vec2.end() - 1); //1,9,8,7,6,2,3,4,5共9个元素,将vec2的9和8添加到vec1的r2位置之前
auto r4 = vec1.insert(r3, 3, 4); //1,4,4,4,9,8,7,6,2,3,4,5在vec1的r3位置之前加入3个4
//删除
std::vector<int> vec3 = { 1,2,3,4,5,6,7,8,9 };
vec3.erase(vec3.end() - 2); //12345679 删除倒数第二个元素
vec3.erase(vec3.end() - 3, vec3.end()); //12345 删除从倒数第三个元素开始,到最后一个元素之间的所有元素
vec3.pop_back(); //1234 删除最后一个元素
vec3.clear(); //相当于vec3.erase(vec3.begin(),vec3.end())
//修改
std::vector<std::string> vec4(3, "abc"); //abc,abc,abc
vec4[1] = "xyz"; //abc,xyz,abc
std::string str1("ooo");
vec4.at(0) = str1; //ooo,xyz,abc
vec4.front() = "front"; //front,xyz,abc
vec4.back() = "back"; //front,xyz,back
std::vector<int> vec5(5, 6); //666666
vec5.assign(3, 4); //444 以3个4替换vec5原来的所有元素
vec5.assign(v1.begin() + 1, v1.end()); //234 用v1第二个元素到最后一个元素替换vec5原来的所有元素
vec5.assign({ 9,9,9 }); //999 用3个9替换vec5原来的所有元素
std::vector<int> vecInt{ 1,2,3,4,5 };
auto it1 = find(vecInt.begin(), vecInt.end(), 3);
if(it1!=vecInt.end())
*it1 = 9; //vecInt = 1,2,9,4,5
//查找
std::vector<int> vec6{ 1,2,3,4,5,6,5 };
auto r5 = vec6.at(0); //1
auto r6 = vec6[1]; //2
auto r7 = vec6.front();//1
auto r8 = vec6.back(); //5
std::vector<int> vec7;
auto r9 = vec7.data();
//auto r10 = *r9; //会出现异常
auto r11 = find(vec6.begin(), vec6.end(), 5); //返回指向5的迭代器,返回的是查找到的第一个迭代器
auto r12 = *(r11 - 1); //4
return 0;
}