vector(一):vector的插入删除
vector是STL中最常用的序列容器之一,结构与数组类似,vector使用连续的存储位置来存储元素,既可以通过偏移量来访问其元素,但是与一般静态数组不同的是Vector实现的是动态数组,动态数组即随着元素的不断插入会动态的容器所占的内存空间,不需要人工对内存空间进行调整
文章目录
vector简介
vector是STL中最常用的序列容器之一,结构与数组类似,vector使用连续的存储位置来存储元素,既可以通过偏移量来访问其元素,但是与一般静态数组不同的是Vector实现的是动态数组,动态数组即随着元素的不断插入会动态的容器所占的内存空间,不需要人工对内存空间进行调整
vector 容器以类模板 vector<T>( T 表示存储元素的类型)的形式定义在 <vector>头文件中,并位于 std 命名空间中。因此,在创建该容器之前,代码中需包含该头文件#include<vector>
vector特点
可变数组大小、支持快速随机访问、在尾部插入或删除元素,在常量时间内就可以完成
vector的成员函数
函数成员 | 函数功能 |
---|---|
begin() | 返回指向容器中第一个元素的迭代器。 |
end() | 返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。 |
rbegin() | 返回指向最后一个元素的迭代器。 |
rend() | 返回指向第一个元素所在位置前一个位置的迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
size() | 返回实际元素个数。 |
max_size() | 返回元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。 |
resize() | 改变实际元素的个数。 |
capacity() | 返回当前容量。 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。 |
reserve() | 增加容器的容量。 |
shrink _to_fit() | 将内存减少到等于当前元素实际所使用的大小。 |
operator[ ] | 重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。 |
at() | 使用经过边界检查的索引访问元素。 |
front() | 返回第一个元素的引用。 |
back() | 返回最后一个元素的引用。 |
data() | 返回指向容器中第一个元素的指针。 |
assign() | 用新元素替换原有内容。 |
push_back() | 在序列的尾部添加一个元素。 |
pop_back() | 移出序列尾部的元素。 |
insert() | 在指定的位置插入一个或多个元素。 |
erase() | 移出一个元素或一段元素。 |
clear() | 移出所有的元素,容器大小变为 0。 |
swap() | 交换两个容器的所有元素。 |
emplace() | 在指定的位置直接生成一个元素。 |
emplace_back() | 在序列尾部生成一个元素。 |
vector的创建
vector对象是依据类模板 vector创建的模板类,在创建vector对象时需要指定存储容器元素的类型
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v1; //①创建vector对象,但并未插入元素,这时并未分配空间
v1.reserve(10); //②在空容器的前提下,reserve()成员函数用来增加容器的容量
vector<int> v2{10,2,8,1,2,14,30}; //③创建vector对象时使用初始化列表的形式来指定初始值和元素个数
vector<int> v3(5); //④指定元素个数,未指定初始值时默认初始值为0
vector<int> v4(5,5); //⑤指定元素个数和初始值
cout<<"*******v1********"<<endl;
cout<<"v1.size="<<v1.size()<<","<<"v1.capacity()="<<v1.capacity()<<endl;
cout<<"*******v2********"<<endl;
for(int i = 0; i < v2.size(); ++i)
{
cout<<"v2["<<i<<"]="<<v2[i]<<endl;
}
cout<<"*******v3********"<<endl;
for(int i = 0; i < v3.size(); ++i)
{
cout<<"v3["<<i<<"]="<<v3[i]<<endl;
}
cout<<"*******v4********"<<endl;
for(int i = 0; i < v4.size(); ++i)
{
cout<<"v4["<<i<<"]="<<v4[i]<<endl;
}
return 0;
}
运行结果
vector的遍历
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void myprintf(T a)
{
cout << a << " ";
}
int main()
{
vector<int> v1{10,2,8,1,2,14,30};
cout<<"*******①下标索引遍历********"<<endl;
for(int i = 0; i < v1.size(); ++i)
{
cout<<"v1["<<i<<"]="<<v1[i]<<endl;
}
cout<<"*******②迭代器遍历********"<<endl;
vector<int>::iterator it;
for(it = v1.begin();it!=v1.end();++it)
{
cout<<(*it)<<endl;
}
cout<<"*******③c++11区间迭代********"<<endl;
for(int i:v1)
{
cout<<i<<endl;
}
cout<<"*******④for_each算法********"<<endl;
for_each(v1.begin(),v1.end(),myprintf<int>);
return 0;
}
运行结果
vector容量与大小
vector的容量与大小是不等价的概念,vector.capacity()可以获取该容器的容量,vector.size()获取容器的大小
- vector.capacity()容量是指在动态扩容的情况下最大可以存储的元素个数
- vector.size()大小是指容器实际情况下存储的元素个数
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int>value{ 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 };
value.reserve(20);
cout << "value 容量是:" << value.capacity() << endl;
cout << "value 大小是:" << value.size() << endl;
return 0;
}
运行结果
容量与大小之间关系
vector容器的大小不能超过容器,若vector大小超过容量则表明当前vector的存储空间不够,需要对vector进行动态扩容
当vector进行扩容时,对于扩容之前vector中所有元素的引用、指针以及迭代器会失效,因为涉及动态扩容会改变原有内存地址
vector插入删除
尾部插入
push_back()、emplace_back()
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> values{};
values.push_back(1);
values.push_back(2);
cout<<"**********push_back插入********"<<endl;
for (int i = 0; i < values.size(); i++) {
cout << values[i] << " ";
}
cout<<endl;
values.emplace_back(1);
values.emplace_back(2);
cout<<"*******emplace_back插入********"<<endl;
for (int i = 0; i < values.size(); i++) {
cout << values[i] << " ";
}
return 0;
}
运行结果
push_back、emplace_back的区别
emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程
指定位置插入
insert()
vector容器提供了 insert() 和 emplace() 这 2 个成员函数,用来实现在容器指定位置处插入元素
语法格式 | 用法说明 |
---|---|
iterator insert(pos,elem) | 在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。 |
iterator insert(pos,n,elem) | 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。 |
iterator insert(pos,first,last) | 在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。 |
iterator insert(pos,initlist) | 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。 |
#include <iostream>
#include <vector>
#include <array>
using namespace std;
int main()
{
std::vector<int> v1{1,2};
cout<<"**********insert(pos,elem)********"<<endl;
v1.insert(v1.begin() + 1, 3);//{1,3,2}
v1.insert(v1.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********insert(pos,n,elem)********"<<endl;
v1.insert(v1.end(), 2, 5);//{1,3,2,5,5}
v1.insert(v1.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********insert(pos,first,last)********"<<endl;
std::array<int,3> t1{ 7,8,9 };
v1.insert(v1.end(), t1.begin(), t1.end());//{1,3,2,5,5,7,8,9}
v1.insert(v1.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********insert(pos,initlist)********"<<endl;
v1.insert(v1.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
return 0;
}
运行结果
emplace()
emplace() 是 C++ 11 标准新增加的成员函数,用于在 vector 容器指定位置之前插入一个新的元素,emplace() 每次只能插入一个元素,而不是多个
#include <vector>
#include <iostream>
using namespace std;
int main()
{
std::vector<int> v1{1,2};
cout<<"**********emplace() 每次只能插入一个 int 类型元素********"<<endl;
v1.emplace(v1.begin(), 3);
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
return 0;
}
运行结果
删除
vector容器删除元素,除了可以借助本身提供的成员函数,还可以借助一些全局函数
函数 | 功能 |
---|---|
pop_back() | 删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量(capacity)不会发生改变。 |
erase(pos) | 删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。 |
swap(beg)、pop_back() | 先调用 swap() 函数交换要删除的目标元素和容器最后一个元素的位置,然后使用 pop_back() 删除该目标元素。 |
erase(beg,end) | 删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会发生改变。 |
remove() | 删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量。 |
clear() | 删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量 |
pop_back()
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> v1{ 1,2,3,4,5 };
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********v1.size()********"<<endl;
cout << "size is :" << v1.size() << endl;
cout<<"**********v1.capacity()********"<<endl;
cout << "capacity is :" << v1.capacity() << endl;
v1.pop_back();
cout<<"**********v1.pop_back()********"<<endl;
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}cout<<endl;
cout<<"**********v1.size()********"<<endl;
cout << "size is :" << v1.size() << endl;
cout<<"**********v1.capacity()********"<<endl;
cout << "capacity is :" << v1.capacity() << endl;
return 0;
}
运行结果
erase()
vector 容器中指定位置处的元素,可以使用 erase() 成员函数对指定位置处的元素进行删除
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> v1{ 1,2,3,4,5 };
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********v1.size()********"<<endl;
cout << "size is :" << v1.size() << endl;
auto iter = v1.erase(v1.begin() + 1);//删除元素 2
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**删除元素之后迭代器指向下一个**"<<endl;
cout<<(*iter)<<endl; //删除元素之后迭代器指向下一个
cout<<"**********v1.erase()********"<<endl;
for (int i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout<<endl;
cout<<"**********v1.size()********"<<endl;
cout << "size is :" << v1.size() << endl;
return 0;
}
运行结果
vector 模板类中提供了 pop_back()、erase()、clear() 等成员方法,可以轻松实现删除容器中已存储的元素。但需要注意得是,借助这些成员方法只能删除指定的元素,容器的容量并不会因此而改变
swap()
vector 模板类中还提供有 swap() 成员方法,该方法的基础功能是交换 2 个相同类型的 vector 容器(交换容量和存储的所有元素),但其也能用于去除 vector 容器多余的容量
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int>myvector;
cout<<"**手动为 myvector 扩容**"<<endl;
myvector.reserve(1000);
cout << "swap()之前、当前 myvector 拥有 " << myvector.size() << " 个元素,容量为 " << myvector.capacity() << endl;
cout<<"**myvector 存储 10 个元素**"<<endl;
for (int i = 1; i <= 10; i++) {
myvector.push_back(i);
}
vector<int>(myvector).swap(myvector);
cout << "swap()之后、当前 myvector 拥有 " << myvector.size() << " 个元素,容量为 " << myvector.capacity() << endl;
cout<<"**swap()清空容器**"<<endl;
vector<int>().swap(myvector);
cout << "swap()之后、当前 myvector 拥有 " << myvector.size() << " 个元素,容量为 " << myvector.capacity() << endl;
return 0;
}
运行结果
运行结果分析
vector<int>(myvector).swap(myvector);
该语句执行流程
1、先执行vector<int>(myvector),调用vector模板类中拷贝构造函数创建一个临时vector对象
2、此时myvector作为复制构造函数的参数传递给临时vector对象,故临时vector对象中存在有myvector中的所有元素
3、又因为拷贝构造函数只会为拷贝的元素分配空间所以临时对象的容量即为大小
4、然后借助swap将临时vector对象与myvector进行交换容量与存储的元素
5、根据上述原理该语句vector<int>().swap(myvector)可以将容器进行清空
总结
vector是STL中最常用的序列容器之一,结构与数组类似,vector使用连续的存储位置来存储元素,既可以通过偏移量来访问其元素,但是与一般静态数组不同的是Vector实现的是动态数组,动态数组即随着元素的不断插入会动态的容器所占的内存空间,支持快速随机访问、在尾部插入或删除元素在常量时间内就可以完成,在指定位置进行插入删除会涉及到元素的移动
希望能和一起学习的人成长,有错误的地方请各位大佬帮忙指正,如果觉得有帮助就点个赞当作对我的一个小肯定❤,peace&love
更多推荐
所有评论(0)