目录
一、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.如何解决迭代器失效
一、vector类
vecotr是可以改变大小的数组的序列容器,其特点有:
(1)vector采用连续空间来存储元素,可以使用下标访问vector元素,访问元素和数组一样方便。vector大小可以动态改变,而且会被容器自动处理,这一点数组无法做到。
(2)vector使用动态分配分配数组来存储元素,插入新元素时,vector数组为了增加存储空间,会分配一个新数组,再把所有元素全部移动到这个数组里,代价相对高一些。
(3)vector会分配额外的空间来满足可能的增长,因为分配的存储空间比实际需要的的存储空间更大。vector以动态增长的方式管理存储空间。
(4)vector在访问元素、末尾添加删除元素时很高效,在其他位置插入删除需要挪动元素,效率低。
二、vector类成员
1.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;
}
2.vector元素访问符
reference operator[] (size_type n); //可读可写
const_reference operator[] (size_type n) const;//只读
//构造空的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; }
2.vector元素访问符
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;
3.vector迭代器
迭代器是一种容器可以统一使用的遍历方式,因此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;
4.vector模板
前面的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
调试-解决方案调试属性-语言-符合模式-否就可以编译通过了
5.vector拷贝构造
vector v6;
v6.push_back(string("delia"));
vector v7(v6);//用v6拷贝构造v7
PrintVector(v7);
vector v8(v5);//用v5拷贝构造v8
PrintVector(v8);
6.vector容量
(1)vector增容机制
在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;
}
}
}
发现增容的过程是大概按照1.5倍增容的
同样的代码在linux下运行,发现是2倍增容的
因此 ,在不同的编译器下增容机制不同。
(2)reserve()和resize()
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
vectorv1; v1.reserve(10); vector v2; v2.resize(10);
(3)size()
返回vector元素个数
size_type size() const;
求v5的size()
vectorv5; //插入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;
(4)empty()
判断vector是否为空,为空返回1,不为空返回0
bool empty() const;
判断v5是否为空
cout << v5.empty() << endl;
7.vetor尾插和尾删
void push_back (const value_type& val);//尾插元素
void pop_back();//尾删元素
向v5尾插元素和尾删元素
v5.push_back(5.5);
PrintVector(v5);
v5.pop_back();
PrintVector(v5);
8.vector在任意位置插入和删除
(1)插入
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 insert (iterator position, const value_type& val);//插入val到position位置 void insert (iterator position, size_type n, const value_type& val);//将n个val插入到position位置 templatevoid insert (iterator position, InputIterator first, InputIterator last);//将值为InputIterator的first到last之间的元素插入到position位置
vectorv5; //插入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);
(2)删除
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()插入删除元素
9.find()
在迭代器区间内查找元素,find函数实现在algorithm中,可以给所有容器使用,因此要使用find函数,就要include
templateInputIterator 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);
10.swap()
将this指针指向的对象的内容和x进行交换
void swap (vector& x);
如:
vectorv1; v1.push_back(20); v.swap(v1);//交换v和v1的元素 PrintVector(v); PrintVector(v1);
vector自己实现了swap(),相比较,库里的swap需要3次深拷贝,代价比较高:
templatevoid swap (T& a, T& b); { T c(a); a=b; b=c; }
三、迭代器失效
1.迭代器失效的情况
(1)在v中插入元素1,2,3,4,5后,在3前面插入30
vectorv; //插入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)如下代码当删除所有偶数时,程序会崩
vectorv; 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变成了野指针
2.如何解决迭代器失效
在使用迭代器之前,对迭代器重新赋值
对于(1)使用迭代器之前,对迭代器重新赋值
vectorv; //插入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不用++
vectorv; 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);



