C++《vector类的使用介绍》

本文详细介绍了C++标准库中的vector容器,包括其构造函数、迭代器的使用、空间增长策略以及reserve和resize函数的区别。vector作为动态数组,提供了高效访问元素和在末尾添加删除元素的功能。文章强调了reserve用于预留空间而不创建对象,而resize则会创建对象并调整容器大小。
摘要由CSDN通过智能技术生成

本文主要介绍vector一些常见的接口函数的使用



一、vector的介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deques, lists and forward_lists), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起lists和forward_lists统一的迭代器和引用更好。

二、vector的使用

2.1vector构造函数

构造函数功能
vector()无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x)(重点)拷贝构造
vector (InputIterator fifirst, InputIterator last) 使用迭代器进行初始化构造
void test1()
{
	vector<int> v1;//无参的构造用的最多
	vector<int> v2(10,1);//用10个1来初始化
	vector<int> v3(v2.begin(),v2.end());//用一段迭代器区间去初始化
	vector<int> v4(v3);//拷贝构造

	string s("hello");
	vector<char> v5(s.begin(), s.end());//不同STL的迭代器区间也可以初始化
}

结果展示:
打开监视窗口观察,确实初始化好了
在这里插入图片描述
问题:
对于下面这种情况:

string s; 和 vector<char> v; 

是不是差不多呢?能不能相互替代呢?

不行的!因为string末尾带着\0,而且string提供了一些专门的字符串相关的接口函数,比如:operator+=c_strfind等等函数

2.2迭代器的使用

iterator的使用功能
begin+end获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator
rebegin+rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置reverse_iterator

在这里插入图片描述

//vector中如何遍历
void test2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	//下标[]遍历
	for (size_t i = 0; i < v.size(); ++i)
	{
		v[i] += 1;
		cout << v[i] << " ";
	}
	cout << endl;

	//迭代器
	//vector<int>::iterator it=v.begin();
	auto it=v.begin();//使用auto更方便
	while (it != v.end())
	{
		
		cout << *it << " ";
		++it;
	}
	cout << endl;
	
	//反向迭代器
   	//vector<int>::reverse_iterator rit = v.rbegin();
   	auto rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	//范围for
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.3空间增长问题

容量函数功能
size( )获取数据个数
capacity( )获取容量大小
empty( )判空
resize( )改变size
reserve( )改变capacity
void test3()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	cout << endl;

//改变capacity
	v.reserve(100);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	cout << endl;
	
//改变size,默认给上缺省值0,它可以 扩容+初始化 或者 删除数据
	v.resize(10,1);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	cout << endl;

//将有效字符缩减为2个(相当于删数据)
	v.resize(2);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	cout << endl;
}

结果展示:
在这里插入图片描述
总结:

  1. capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,顺序表增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
  2. reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  3. resize在开空间的同时还会进行初始化,影响size。

我们可以测试一下不同版本扩容的情况:

//测试扩容
void test_VectorExpand()
{
	size_t sz;
	const size_t n = 100;
	vector<int> v1;

	sz = v1.capacity();
	for (size_t i = 0; i < n; ++i)
	{
		v1.push_back(i);
		if (sz != v1.capacity())
		{
			sz = v1.capacity();
			cout << "capacity chang" << sz << endl;
		}
	}
}

VS下结果:
在这里插入图片描述

g++下:
在这里插入图片描述

2.4增删查改问题

函数功能
push_back( )尾插
pop_back( )尾删
insert( )在pos之前插入
erase( )删除
swap( )交换两个vector的数据空间
operator[ ]下标位置访问
find( )这个是算法库里面实现的查找(algorithm),不是vector的成员函数
void test_vector5()
{
	vector<int> v;
//尾插数据
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

//指定pos位置插入
	//insert
	//vector<int>::iterator pos = find(v.begin(), v.end(), 2);
	auto pos = find(v.begin(), v.end(), 2);
	if (pos != v.end())
	{
		v.insert(pos, 100);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

//尾删数据
	//pop_back
	v.pop_back();
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

//find查找数据	
	pos = find(v.begin(), v.end(), 2);
	if (pos != v.end())
	{
		v.erase(pos);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

//erase支持迭代器删除数据(头删)
	v.erase(v.begin());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

//erase删除区间
	v.erase(v.begin(), v.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

vector::swap的使用
void swap (vector& x);

void test_vector6()
{
	vector<int> v1(10, 1);
	vector<int> v2(10, 2);

	v2.swap(v1);
}

说明:vector是支持迭代器的,还可以用范围for对vector进行遍历,支持迭代器就支持范围for,因为在编译时编译器会自动将范围for替换为迭代器遍历的形式。

三、vector中reserve和resize的区别

reserve:

1**:reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。不能使用[]访问元素**

resize:

resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。

再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。

下面是这两个函数使用例子:


//错误代码
int main()
{
    int n;
    cin >> n;
    vector<int> a;
    a.reserve(n);//新元素还没有构造,不能使用[]
    for(int i = 0; i < n;i++)
    {
        cin >> a[i];//错误!!!!!!
    }
    return 0;
}


//正确代码
int main()
{
    int n;
    cin >> n;
    vector<int> a;
    a.resize(n);//新元素构造了可以使用[]
    for(int i = 0; i < n;i++)
    {
        cin >> a[i];
    }
    return 0;
}
vector<int> myVec;
 
 
myVec.reserve( 100 );     // 新元素还没有构造
 
                          // 此时不能用[]访问元素
 
for (int i = 0; i < 100; i++ )
{
	myVec.push_back( i ); //新元素这时才构造
}
 
 
myVec.resize( 102 );      // 用元素的默认构造函数构造了两个新的元素
 
myVec[100] = 1;           //直接操作新元素
 
myVec[101] = 2;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值