文章目录
1.vector容器特性
动态数组,可变数组。
单口容器。
在尾部插入:push_back()
在尾部弹出:pop_back()
在中间插入:insert()
迭代器:v.begin()和v.end()
反向迭代器:v.rbegin()和v.rend()
2.vector动态增长原理
vector实现了动态增长:当插入新元素的时候,如果空间不足,那么vector会重新申请更大的一块内存空间(默认原始空间大小两倍),将圆空间数据拷贝到新的空间,释放旧空间的数据,再把新元素插入新申请的空间。
2.1.vector内存申请测试
在vector尾部循环插入一个数据,同时观察vector的capacity、size、vector首地址,看变化趋势。
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v1;
cout<<"初始:cap:"<<v1.capacity()<<",size:"<<v1.size()<<endl;
for(int i=0;i<65;i++)
{
v1.push_back(i); //尾部插入一个数据
cout<<"cap:"<<v1.capacity()<<",size:"<<v1.size()<<",vector_add:"<<&v1[0]<<endl;
}
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 04vecto.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
初始:cap:0,size:0
cap:1,size:1,vector_add:0x55f450486280
cap:2,size:2,vector_add:0x55f4504862a0
cap:4,size:3,vector_add:0x55f450486280
cap:4,size:4,vector_add:0x55f450486280
cap:8,size:5,vector_add:0x55f4504862c0
cap:8,size:6,vector_add:0x55f4504862c0
cap:8,size:7,vector_add:0x55f4504862c0
cap:8,size:8,vector_add:0x55f4504862c0
cap:16,size:9,vector_add:0x55f4504862f0
cap:16,size:10,vector_add:0x55f4504862f0
cap:16,size:11,vector_add:0x55f4504862f0
cap:16,size:12,vector_add:0x55f4504862f0
cap:16,size:13,vector_add:0x55f4504862f0
cap:16,size:14,vector_add:0x55f4504862f0
cap:16,size:15,vector_add:0x55f4504862f0
cap:16,size:16,vector_add:0x55f4504862f0
cap:32,size:17,vector_add:0x55f450486340
cap:32,size:18,vector_add:0x55f450486340
cap:32,size:19,vector_add:0x55f450486340
cap:32,size:20,vector_add:0x55f450486340
cap:32,size:21,vector_add:0x55f450486340
cap:32,size:22,vector_add:0x55f450486340
cap:32,size:23,vector_add:0x55f450486340
cap:32,size:24,vector_add:0x55f450486340
cap:32,size:25,vector_add:0x55f450486340
cap:32,size:26,vector_add:0x55f450486340
cap:32,size:27,vector_add:0x55f450486340
cap:32,size:28,vector_add:0x55f450486340
cap:32,size:29,vector_add:0x55f450486340
cap:32,size:30,vector_add:0x55f450486340
cap:32,size:31,vector_add:0x55f450486340
cap:32,size:32,vector_add:0x55f450486340
cap:64,size:33,vector_add:0x55f4504863d0
cap:64,size:34,vector_add:0x55f4504863d0
cap:64,size:35,vector_add:0x55f4504863d0
cap:64,size:36,vector_add:0x55f4504863d0
cap:64,size:37,vector_add:0x55f4504863d0
cap:64,size:38,vector_add:0x55f4504863d0
cap:64,size:39,vector_add:0x55f4504863d0
cap:64,size:40,vector_add:0x55f4504863d0
cap:64,size:41,vector_add:0x55f4504863d0
cap:64,size:42,vector_add:0x55f4504863d0
cap:64,size:43,vector_add:0x55f4504863d0
cap:64,size:44,vector_add:0x55f4504863d0
cap:64,size:45,vector_add:0x55f4504863d0
cap:64,size:46,vector_add:0x55f4504863d0
cap:64,size:47,vector_add:0x55f4504863d0
cap:64,size:48,vector_add:0x55f4504863d0
cap:64,size:49,vector_add:0x55f4504863d0
cap:64,size:50,vector_add:0x55f4504863d0
cap:64,size:51,vector_add:0x55f4504863d0
cap:64,size:52,vector_add:0x55f4504863d0
cap:64,size:53,vector_add:0x55f4504863d0
cap:64,size:54,vector_add:0x55f4504863d0
cap:64,size:55,vector_add:0x55f4504863d0
cap:64,size:56,vector_add:0x55f4504863d0
cap:64,size:57,vector_add:0x55f4504863d0
cap:64,size:58,vector_add:0x55f4504863d0
cap:64,size:59,vector_add:0x55f4504863d0
cap:64,size:60,vector_add:0x55f4504863d0
cap:64,size:61,vector_add:0x55f4504863d0
cap:64,size:62,vector_add:0x55f4504863d0
cap:64,size:63,vector_add:0x55f4504863d0
cap:64,size:64,vector_add:0x55f4504863d0
cap:128,size:65,vector_add:0x55f4504864e0
结果分析(自我理解):
vector初始capacity和size都是0;
在一个个向尾部添加数据后,当vector空间不足以存储数据时,申请更大的空间以存储新插入的数据。申请空间的总大小为当前空间大小的两倍。
当申请更大空间时,首地址发生变化:说明存储位置是全新的,不是在原来的数组尾部地址后面扩展(无法确定尾部后面地址空间是否已经被其他数据占用,干脆重新申请一块两倍大小的空间,让系统自己去分配地址)。
3.vector初始化
3.1.vector构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); //将v[begin(), end()]区间中的元素拷贝给本身
vector(n, elem); //构造函数将n个elem拷贝给本身
vector(const vector &vec); //拷贝构造函数
例子:使用第二个构造函数,可以
int arr[] = {2,3,4,1,9};
vector<int> v1(arr, arr+sizeof(arr)/sizeof(int));
3.2.vector初始化举例
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
//打印vector中元素
void printvector(vector<int>& v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
//初始化
int main()
{
vector<int> v1; //默认构造函数
int arr[] = {10,20,30,40};
vector<int> v2(arr,arr+sizeof(arr)/sizeof(int));
vector<int> v3(v2.begin(), v2.end());
vector<int> v4(v3);
printvector(v2);
printvector(v3);
printvector(v4);
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
10 20 30 40
10 20 30 40
10 20 30 40
4.vector常用赋值操作
4.1.vector赋值操作函数
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem); //将n个elem拷贝赋值给本身。
vector& operator=(const vector &vec); //重载等号操作符
swap(vec); //将vec与本身的元素互换
4.2.vector赋值操作函数举例
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
void printvector(vector<int>& v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
//初始化
int main()
{
int arr[] = {10,20,30,40};
//构造函数
vector<int> v1(arr,arr+sizeof(arr)/sizeof(int));
//成员方法
vector<int> v2;
v2.assign(v1.begin(), v1.end());
//重载=
vector<int> v3;
v3 = v2;
int arr1[] = {100,200,300,400};
vector<int> v4(arr1, arr1+sizeof(arr1)/sizeof(int));
cout<<"======互换前打印======"<<endl;
printvector(v1);
printvector(v2);
printvector(v3);
printvector(v4);
//互换元素,注意不是赋值
v4.swap(v1);
cout<<"======互换后打印======"<<endl;
printvector(v1);
printvector(v2);
printvector(v3);
printvector(v4);
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 02vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
======互换前打印======
10 20 30 40
10 20 30 40
10 20 30 40
100 200 300 400
======互换后打印======
100 200 300 400
10 20 30 40
10 20 30 40
10 20 30 40
5.vector大小操作
5.1.vector大小操作函数
size(); //返回容器中元素个数
empty(); //判断容器是否为空
resize(int num); //重新指定容器的长度num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
capacity(); //容器的容量
reserve(int len); //容器预留一个len个元素长度,预留位置不初始化,元素不可访问。
5.2.vector大小操作函数举例
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
void printvector(vector<int>& v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
//初始化
int main()
{
int arr[] = {10,20,30,40};
vector<int> v2(arr,arr+sizeof(arr)/sizeof(int));
cout<<"size:"<<v2.size()<<endl;
if(v2.empty())
{
cout<<"空!"<<endl;
return 0;
}
else
{
cout<<"非空!"<<endl;
}
cout<<"v2:";
printvector(v2);
v2.resize(2);
cout<<"v2.resize(2):";
printvector(v2);
v2.resize(6);
cout<<"v2.resize(6):";
printvector(v2);
v2.resize(8,1);
cout<<"v2.resize(8,1):";
printvector(v2);
cout<<"v2.size():"<<v2.size()<<endl;
cout<<"v2.capacity():"<<v2.capacity()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 03vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
size:4
非空!
v2:10 20 30 40
v2.resize(2):10 20
v2.resize(6):10 20 0 0 0 0
v2.resize(8,1):10 20 0 0 0 0 1 1
v2.size():8
v2.capacity():12
6.vector数据存取操作
6.1.vector存取操作函数
at(int idx); //返回索引idx所指的数据,如果idx越界,跑出out_of_range异常。
operator[]; //返回索引idx所指的数据,越界时,运行直接报错。
front(); //返回容器中第第一个数据元素
back(); //返回容器中最后一个数据元素
6.2.vector存取举例
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
int arr[] = {10,20,30,40};
vector<int> v1(arr,arr+sizeof(arr)/sizeof(int));
//v.at(i)成员函数
cout<<"v.at(i):";
for(int i=0;i<v1.size();i++)
{
cout<<v1.at(i)<<" ";
}
cout<<endl;
//v[i],[]运算符
cout<<"v[i]:";
for(int i=0;i<v1.size();i++)
{
cout<<v1[i]<<" ";
}
cout<<endl;
//v.front()成员函数
cout<<"v.front():"<<v1.front()<<endl;
//v.back()成员函数
cout<<"v.back():"<<v1.back()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 04vecto.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
v.at(i):10 20 30 40
v[i]:10 20 30 40
v.front():10
v.back():40
7.vector插入和删除操作
7.1.vector插入和删除函数
insert(const_iterator pos, int count,ele); //向迭代器指向位置pos插入count个元素ele
push_back(ele); //尾部插入元素ele
pop_back(); //删除最后一个元素
erase(const_iterator start,const_iterator end); //删除迭代器从start到end之间的元素,不包括end
erase(const_iterator pos); //删除迭代器指向的元素
clear(); //删除容器中所有元素
7.2.vector插入删除举例
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
void printvector(vector<int>& v)
{
for(vector<int>::iterator it = v.begin();it != v.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
//使用迭代器插入
v.insert(v.begin(),30);
v.insert(v.end(),40);
printvector(v);
//支持数组下标,一般都支持随机访问
//vector迭代器可以直接+2,+3,-1操作
v.insert(v.begin()+2,100);
printvector(v);
//删除
v.erase(v.begin()); //删除单个元素
printvector(v);
v.erase(v.begin()+1,v.end()); //删除整个区间元素
printvector(v);
//清空
v.clear();
cout<<"size:"<<v.size()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 05vecto.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
30 10 20 40
30 10 100 20 40
10 100 20 40
10
size:0
8.巧用swap收缩vector空间
8.1.resize()减小vector后,capacity是否减小?
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v;
for(int i=0;i<10000;i++)
{
v.push_back(i);
}
cout<<"resize前:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
v.resize(10);
cout<<"resize后:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 06vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
resize前:capacity:16384,size:10000
resize后:capacity:16384,size:10
执行结果分析:
resize减少了vector元素个数,但是capacity并没有随着减小,占用了不必要的空间。
8.2.巧用swap收缩vector空间
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v;
for(int i=0;i<10000;i++)
{
v.push_back(i);
}
cout<<"resize前:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
v.resize(10);
cout<<"resize后:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
//收缩空间,交换
vector<int>(v).swap(v);
cout<<"swap后:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 06vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
resize前:capacity:16384,size:10000
resize后:capacity:16384,size:10
swap后:capacity:10,size:10
结果分析:
vector<int>(v).swap(v);
vector<int>
声明的无名对象,使用v
去初始化无名对象,然后对无名对象调用swap()函数,和v互换。无名对象使用完后自动释放。
8.3.上例swap收缩vector空间的另一种拆分写法
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v;
for(int i=0;i<10000;i++)
{
v.push_back(i);
}
cout<<"resize前:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
v.resize(10);
cout<<"resize后:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
//收缩空间
vector<int> v_tmp(v);
cout<<"swap前:v_tmp.capacity:"<<v_tmp.capacity()<<",v_tmp.size:"<<v_tmp.size()<<endl;
v_tmp.swap(v);
cout<<"swap后:capacity:"<<v.capacity()<<",size:"<<v.size()<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 06vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
resize前:capacity:16384,size:10000
resize后:capacity:16384,size:10
swap前:v_tmp.capacity:10,v_tmp.size:10
swap后:capacity:10,size:10
9.reserve预留空间提高效率
9.1.如果不使用reserve,重新申请空间次数
在vector尾部逐个添加元素,查看vector自动重新申请空间的次数。
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v;
int* v_add = NULL;
int num;
for(int i=0;i<10000;i++)
{
v.push_back(i);
if(v_add != &(v[0]))
{
cout<<"add["<<i<<"]:"<<&(v[0]<<endl;
v_add = &v[0];
num ++;
}
}
cout<<"num:"<<num<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 07vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
add[0]:0x564d1ec4ae70
add[1]:0x564d1ec4b2a0
add[2]:0x564d1ec4ae70
add[4]:0x564d1ec4b2c0
add[8]:0x564d1ec4b2f0
add[16]:0x564d1ec4b340
add[32]:0x564d1ec4b3d0
add[64]:0x564d1ec4b4e0
add[128]:0x564d1ec4b6f0
add[256]:0x564d1ec4bb00
add[512]:0x564d1ec4c310
add[1024]:0x564d1ec4d320
add[2048]:0x564d1ec4f330
add[4096]:0x564d1ec53340
add[8192]:0x564d1ec5b350
num:15
9.1.如果使用reserve预留空间,不需要重新申请
预留足够空间后,空间足够使用,所以不需要再一次次申请。
#include <iostream>
#include <vector> //vector需要包含的头文件
using namespace std;
int main()
{
vector<int> v;
int* v_add = NULL;
int num;
v.reserve(10000);
for(int i=0;i<10000;i++)
{
v.push_back(i);
if(v_add != &(v[0]))
{
cout<<"add["<<i<<"]:"<<&v[0]<<endl;
v_add = &v[0];
num ++;
}
}
cout<<"num:"<<num<<endl;
return 0;
}
执行结果:
root@host:/home/LinuxShare/007.STL# g++ 07vector.cpp
root@host:/home/LinuxShare/007.STL# ./a.out
add[0]:0x556c13abde70
num:1