vector常见接口的使用以及迭代器失效问题

  • 对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;
      }
   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值