目录
一、vector类
二、vector类成员
1.vector类对象构造
2.vector元素访问符
3.vector迭代器
4.vector模板
5.vector拷贝构造
6.vector容量
(1)vector增容机制
(2)reserve()和resize()
(3)size()
(4)empty()
7.vetor尾插和尾删
8.vector在任意位置插入和删除
(1)插入
(2)删除
9.find()
10.swap()
三、迭代器失效
1.迭代器失效的情况
2.如何解决迭代器失效
vecotr是可以改变大小的数组的序列容器,其特点有:
(1)vector采用连续空间来存储元素,可以使用下标访问vector元素,访问元素和数组一样方便。vector大小可以动态改变,而且会被容器自动处理,这一点数组无法做到。
(2)vector使用动态分配分配数组来存储元素,插入新元素时,vector数组为了增加存储空间,会分配一个新数组,再把所有元素全部移动到这个数组里,代价相对高一些。
(3)vector会分配额外的空间来满足可能的增长,因为分配的存储空间比实际需要的的存储空间更大。vector以动态增长的方式管理存储空间。
(4)vector在访问元素、末尾添加删除元素时很高效,在其他位置插入删除需要挪动元素,效率低。
//构造空的vector
explicit vector (const allocator_type& alloc = allocator_type());
//构造一个vector,有n个元素,每个元素值为val
explicit vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
//构造一个vector,值为InputIterator的first到last之间的元素
template
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
//使用x拷贝构造一个vector
vector (const vector& x);
#include
#include
using namespace std;
int main()
{
vector v;//构造一个没有元素的空容器
vector v1(3, 5);//构造一个有3个元素的容器,每个元素的值都为5
vector v2(v1.begin(),v1.end());//构造一个从v1.begin()到v1.end()顺序及相同值的容器
vector v3(v2);//以与v2相同的顺序及值拷贝构造一个容器
//插入4个元素
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
return 0;
}
reference operator[] (size_type n); //可读可写
const_reference operator[] (size_type n) const;//只读
vector使用operator[ ]遍历元素,像数组一样:
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
迭代器是一种容器可以统一使用的遍历方式,因此vector也支持使用迭代器遍历
iterator begin(); //可读可写
const_iterator begin() const;//只读
iterator end(); //可读可写
const_iterator end() const; //只读
reverse_iterator rbegin(); //反向迭代器 可读可写
const_reverse_iterator rbegin() const; //反向迭代器 只读
reverse_iterator rbegin(); //反向迭代器 可读可写
const_reverse_iterator rbegin() const; //反向迭代器 只读
(1)迭代器
①可读可写
vector::iterator it = v.begin();//可读可写
while (it != v.end())
{
*it += 2;
cout << *it << " ";
it++;
}
cout << endl;
②只读
vector::const_iterator it = v.begin();//只读
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
(2)反向迭代器 (这段代码屏蔽了(1)的迭代器)
①可读可写
vector::reverse_iterator rit = v.rbegin();//可读可写
while (rit != v.rend())
{
*rit += 2;
cout << *rit << " ";
rit++;
}
cout << endl;
②只读
vector::const_reverse_iterator rit = v.rbegin();//只读
while (rit != v.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
前面的PrintVector( )只能打印元素为int的vector,如果vector元素类型不是int,而是char或float类型,该如何打印呢?使用模板可以实现,有关模板的详细说明请阅读文章【C++】-- 模板详解
//打印
template//类模板定义
void PrintVector(const vector& v)
{
//指定参数类型
vector::const_iterator it = v.begin();//只读
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
int main()
{
vector v;//定义一个vector,该vector里面的元素都是int型的
//插入4个int元素
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
PrintVector(v);
string s1 = "Hello world";
vector v4(s1.begin(), s1.end());
PrintVector(v4);
vector v5;
插入4个float元素
v5.push_back(1.1);
v5.push_back(2.2);
v5.push_back(3.3);
v5.push_back(4.4);
PrintVector(v5);
return 0;
}
注:如果编译报vector
vector v6;
v6.push_back(string("delia"));
vector v7(v6);//用v6拷贝构造v7
PrintVector(v7);
vector v8(v5);//用v5拷贝构造v8
PrintVector(v8);
在VS下执行这段代码:
void test_vector3()
{
size_t sz;
std::vector 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 << endl;
}
}
}
同样的代码在linux下运行,发现是2倍增容的
因此 ,在不同的编译器下增容机制不同。
void reserve (size_type n);//开辟n个元素空间
void resize (size_type n, value_type val = value_type());//开辟n个元素空间,并将每个元素默认初始化为val
如果加上reserve(),那么会提前知道要开多少空间,就提前开好了,避免后面再开空间
void test_vector3()
{
size_t sz;
std::vector foo;
sz = foo.capacity();
foo.reserve(100);
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 << endl;
}
}
}
linux下运行也是同样结果 ,也是提前知道要开100个字节的空间,就提前开好了
监视如下代码发现,reserve()之后,capacity变了,但是size没变;resize()之后,capacity变了,size也变了,且每个元素都被默认赋值为0
vector v1;
v1.reserve(10);
vector v2;
v2.resize(10);
返回vector元素个数
size_type size() const;
求v5的size()
vector v5;
//插入4个元素
v5.push_back(1.1);
v5.push_back(2.2);
v5.push_back(3.3);
v5.push_back(4.4);
cout << v5.size() << endl;
判断vector是否为空,为空返回1,不为空返回0
bool empty() const;
判断v5是否为空
cout << v5.empty() << endl;
void push_back (const value_type& val);//尾插元素
void pop_back();//尾删元素
向v5尾插元素和尾删元素
v5.push_back(5.5);
PrintVector(v5);
v5.pop_back();
PrintVector(v5);
iterator insert (iterator position, const value_type& val);//插入val到position位置
void insert (iterator position, size_type n, const value_type& val);//将n个val插入到position位置
template
void insert (iterator position, InputIterator first, InputIterator last);//将值为InputIterator的first到last之间的元素插入到position位置
vector v5;
//插入4个float元素
v5.push_back(1.1);
v5.push_back(2.2);
v5.push_back(3.3);
v5.push_back(4.4);
v5.push_back(5.5);
v5.insert(v5.end(), 6.6);//在v5末尾插入6.6
PrintVector(v5);
v5.insert(v5.begin(), 2,0);//在v5开头插入2个0
PrintVector(v5);
vector v6;
v6.push_back(7.7);
v6.push_back(8.8);
v5.insert(v5.begin(), v6.begin(),v6.end());//在v5开头插入v6
PrintVector(v5);
iterator erase (iterator position);//删除某一位置元素
iterator erase (iterator first, iterator last);//删除迭代器first和last之间的元素
v5.erase(v5.begin());//删除v5开头元素
PrintVector(v5);
v5.erase(v5.begin(), v5.begin()+2);//从v5开头删除2个元素
PrintVector(v5);
insert()和erase()之后需要挪动元素,时间复杂度为O(N),效率较低,不推荐用insert()和erase()插入删除元素
在迭代器区间内查找元素,find函数实现在algorithm中,可以给所有容器使用,因此要使用find函数,就要include
template
InputIterator find (InputIterator first, InputIterator last, const T& val);//在InputIterator迭代器first和last区间内查找val元素的位置
注意:迭代器区间是左闭右开,因此能取到第一个位置,但取不到最后一个位置
vector::iterator pos = find(v5.begin(), v5.begin() + 3, 1.1);//在第一个元素和第四个元素(左闭右开,不包含第四个元素)之间查找值为1.1的元素位置
v5.erase(pos);//删除1.1位置的元素,即删除1.1
PrintVector(v5);
将this指针指向的对象的内容和x进行交换
void swap (vector& x);
如:
vector v1;
v1.push_back(20);
v.swap(v1);//交换v和v1的元素
PrintVector(v);
PrintVector(v1);
vector自己实现了swap(),相比较,库里的swap需要3次深拷贝,代价比较高:
template void swap (T& a, T& b);
{
T c(a); a=b; b=c;
}
(1)在v中插入元素1,2,3,4,5后,在3前面插入30
vector v;
//插入6个int元素
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//在3的前面插入30
vector::iterator pos = find(v.begin(), v.end(), 3);//查找3的位置
if (pos != v.end())
{
v.insert(pos, 30);
}
PrintVector(v);
但是当删除30时,执行如下代码,程序崩了
v.erase(pos);
PrintVector(v);
这是因为先查找3,找到后挪动3的位置及之后的数据,插入30,3已经挪走了,但pos还指向原来的位置,也就是现在30的位置。再erase的时候,pos失效了,因为pos的意义变了,不再指向3了,所以程序崩溃。
(2)如下代码当删除所有偶数时,程序会崩
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
//删除v中所有的偶数
vector::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
}
it++;
}
PrintVector(v);
执行过程:end不固定,删除数据后,每次都会去重新拿取,end是最后一个数的下一个位置
而且执行过程中,由于删除数据后,it++了,迭代器的意义变了,所以结果一定不正确。
迭代器失效有两种情况:
(1)pos意义变了,插入数据以后,pos不再指向3,而是指向30,导致erase(pos)没有达到删除3的目的,反而删除的是30
(2)程序可能崩溃,pos变成了野指针
在使用迭代器之前,对迭代器重新赋值
对于(1)使用迭代器之前,对迭代器重新赋值
vector v;
//插入6个int元素
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//在3的前面插入30
vector::iterator pos = find(v.begin(), v.end(), 3);
if (pos != v.end())
{
v.insert(pos, 30);
}
PrintVector(v);
//使用迭代器之前,对迭代器重新赋值
pos = find(v.begin(), v.end(), 3);
//然后再使用迭代器
if (pos != v.end())
{
v.erase(pos);
}
PrintVector(v);
对于(2)每次使用迭代器之前,对迭代器重新赋值,当it为偶数的位置时,删除偶数后,it不用++
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
//删除v中所有的偶数
vector::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
//每次使用迭代器之前,对迭代器重新赋值
it = v.erase(it);//删除偶数后,it不用++
}
else
{
it++;//奇数,it++
}
}
PrintVector(v);