- 对vector的介绍
1.vector是表示可变大小数组的序列容器。
2.跟数组一样,vector也采用连续的存储空间来存储元素,这就意味着可以采用下标对vector的元素进行访问,和数组一样高效。但它又不像数组,它的大小可以动态改变,而且它的大小会被容器自动处理。
3.本质讲,vector使用动态分配数组来存储它的元素,当有新元素插入的时候,这个数组需要被重新分配大小,为了增加存储空间,做法就是,分配一个新的数组,然后将全部的元素移到这个数组。就时间而言,代价比较高,因为每当一个新元素加入到容器时,vector并不会每次斗重新分配大小。
4.vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。不管怎样,重新分配都应该是对数增长的间隔大小,以至于再末尾插入一个元素时是在常数时间的复杂度内完成的。
5.与其他动态序列容器相比,vector在访问元素是更加高效,在末尾添加和删除元素相对高效,但对于其他不在末尾删除和插入的操作效率更低。 - vector的使用
1.vector的定义
构造函数声明 | 接口说明 |
---|---|
vector() | 无参构造 |
vector(size_type n, const value_type& val = value_type() | 构造并初始化n个val |
vector (const vector& x) | 拷贝构造 |
vector (InputIterator first, InputIterator last) | 使用迭代器进行初始化构造 |
代码举例:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v1;//int型的空vector
vector<int> v2(4, 10);//4个10
vector<int> v3(v2.begin(), v2.end());//迭代v2中的元素
vector<int> v4(v3);//拷贝v3
return 0;
}
2.vector iterator的使用
iterator的使用 | 接口说明 |
---|---|
begin() | 获取第一个数据位置的iterator |
end() | 获取最后一个数据的下一个位置的iterator |
rbegin() | 获取最后一个数据的reverse_iterator |
rend() | 获取第一个数据前一个位置的reverse_iterator |
cbegin() | 获取第一个数据位置的const_iterator |
cend() | 获取最后一个数据的下一个位置的const_iterator |
使用迭代器进行遍历打印:
#include<iostream>
#include<vector>
using namespace std;
void PrintVector(const vector<int>& v)
{
//使用const迭代器进行遍历打印,注意const迭代器不能修改vector的内容
vector<int>::const_iterator it = v.cbegin();
while (it != v.cend())
{
cout << *it << " ";
++it;
}
cout << endl;
}
int main()
{
//使用push_back
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//使用迭代器进行遍历打印
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//使用迭代器进行修改
it = v.begin();
while (it != v.end())
{
*it *= 2;
++it;
}
PrintVector(v);
//使用反向迭代器进行遍历打印
vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
return 0;
}
运行结果:
3.vector的空间增长问题:
容量空间 | 接口说明 |
---|---|
size | 获取vector的元素个数 |
max_size | 返回vector最大的size |
resize | 改变vector的大小 |
capacity | 返回vector的容量大小 |
empty | 判断vector是否为空 |
reserve | 改变vector的容量 |
注意:
1)capacity的代码在vs和g++下分别运行会发现,在vs下capacity是按1.5倍增长的,在g++下是按2倍增长的。不能固化的认为顺序表增容都是按2倍增长,具体增长多少是根据具体的需求定义的。
2)reserve只负责开辟空间,如果确定知道需要多少空间,reserve可以缓解vector增容的代价缺陷问题。
3)resize在开辟空间的同时还会进行初始化,影响size的大小。
看下面的代码:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
size_t sz;
std::vector<int> foo;
sz = foo.capacity();
std::cout << "making foo grow:\n";
for (int i = 0; i < 100; ++i)
{
foo.push_back(i);
if (sz != foo.capacity())
{
sz = foo.capacity();
std::cout << "capacity changed:" << sz << '\n';
}
}
return 0;
}
运行结果:
可以看出capacity是按1.5倍增长的。
4.vector的增删查改:
vector的增删查改 | 接口说明 |
---|---|
assign | 给vector赋值 |
void push_back (const value_type& val); | 尾插元素 |
void pop_back(); | 删除最后一个元素 |
iterator insert (iterator position, const value_type& val); | 插入元素 |
iterator erase(iterator position; | 删除position位置的元素 |
clear | 清理元素 |
InputIterator find (InputIterator first, InputIterator last, const T& val); | 查找(这个是算法模块实现,不是vector的成员接口) |
void swap (vector& x); | 交换两个vector的元素空间 |
reference operator[] (size_type n); | 像数组一样访问 |
//push_back、pop_back的相关运用
int main()
{
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a)/sizeof(int));//使用的是迭代器进行初始化构造
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
v.pop_back();
v.pop_back();
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
运行结果:
//find、insert、erase的相关运用
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a)/sizeof(int));
vector<int>::iterator pos = find(v.begin(), v.end(), 3);//使用find查找3所在位置的iterator
v.insert(pos, 10);//在pos位置之前插入10
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
pos = find(v.begin(), v.end(), 3);
v.erase(pos);//删除pos位置的元素
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
运行结果:
vector的几种遍历方式:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a) / sizeof(int));
//通过[]读写第0个位置
v[0] = 10;
cout << v[0] << endl;
//通过[i]的方式遍历vector
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " ";
}
cout << endl;
//C++11支持的新式遍历
for (auto x : v)
{
cout << x << " ";
}
cout << endl;
return 0;
}
运行结果:
- vector迭代器失效问题
//inser/erase导致的迭代器失效
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a)/sizeof(int));
vector<int>::iterator pos = find(v.begin(), v.end(), 3);//使用find查找3所在位置的iterator
v.erase(pos);//删除pos位置的数据导致pos迭代器失效
cout<<*pos<<endl;//已经删除了pos,再次访问就属于非法访问了
pos = find(v.begin(),v.end(),3);
//在pos位置插入数据导致迭代器失效
//insert导致迭代器失效是因为insert可能会导致增容,增容后的pos任然指向原来的空间,而原来的空间已经被释放了
v.insert(pos,100);
cout<<*pos<<endl;
return 0;
}
常见的迭代器失效场景:
#include<iostram>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
int a[] = {1,2,3,4,5,6};
vector<int> v(a,sizeof(a)/sizeof(int));
vector<int>::iterator it = v.begin();
while(it != v.end())
{
if(*it % 2 == 0)
{
v.erase(it);
++it;
}
}
return 0;
}
以上代码的功能是删除v中的偶数,一旦erase掉it,it指针就消失了,再++it就会导致程序崩溃。改进方法:
vector<int>::iterator it = v.begin();
while(it != v.end())
{
if(*it % 2 == 0)
{
it = v.erase(it);//erase返回删除位置的下一个位置,所以就用it再次记录删除位置的下一个位置
}
else
{
++it;
}
}