C++STL——vector容器详解

在这里插入图片描述
纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。

一.vector容器基本概念

vector的数据安排以及操作方式,与array非常相似,都是一片连续的储存空间,两者的唯一差别在于空间的运用的灵活性。

array是静态数组,一旦配置了空间就无法再改变,要换大一点或者小一点的空间,可以,一切琐碎得由自己来,首先配置一块新的空间,然后将旧空间的数据搬往新空间,再释放原来的空间。

vector是动态空间(动态数组),随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的合理利用与运用的灵活性有很大的帮助,我们再也不必害怕空间不足而一开始就要求一个大块头的array了。

在这里插入图片描述

①vector的实现技术:
vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,一旦vector旧空间满了,如果客户每新增一个元素,vector内部只是扩充一个元素的空间,实为不智,因为只要是扩充空间(不论多大),其步骤就是“配置新空间-数据移动-释放旧空间”的大工程,时间成本很高,所以为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充,这边是容量的概念。换句话说,一个vector的容量永远大于或等于其大小,一旦容量等于大小,便是满载,下次再有新增元素,整个vector容器就得另觅居所(配置新空间-数据移动-释放旧空间)。
②vector迭代器:
vector维护一个线性空间,所以不论元素的型别如何,普通指针都可以作为vector的迭代器,因为vector迭代器所需要的操作行为,如operaroe*, operator->, operator++, operator–, operator+, operator-, operator+=, operator-=, 普通指针天生具备。vector支持随机存取,而普通指针正有着这样的能力。所以vector提供的是随机访问迭代器(Random Access Iterators).
③vector的数据结构:
vector所采用的数据结构非常简单,线性连续空间,它以两个迭代器_Myfirst和_Mylast分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器_Myend指向整块连续内存空间的尾端。
④注意:

所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是分配一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。

二.vector常用操作

①vector构造函数

注:使用vector容器时,需包含头文件#include < vector>

函数解释
vector< T > v;采用模板实现类实现(显示实例化),默认构造函数,
vector(v.begin(), v.end());将v[begin(), end())区间中的元素拷贝给本身
vector(n, elem);构造函数将n个elem拷贝给本身。
vector(const vector &vec);拷贝构造函数,拿另一个vector对象初始化本身

实例:vector构造函数

#include <iostream> 
#include<vector> 
using namespace std;
void printvector(const vector<int>& vec)
{
    for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
    {
        cout << *it;
    }
    cout << endl;
}
int main()
{
    vector<int> v1 = { 1,2,3 };//采用模板实现类实现(显示实例化),默认构造函数,
    vector<int> v2(6,1);//构造函数将n个elem拷贝给本身。
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    vector<int> v3(arr, arr+sizeof(arr)/ sizeof(arr[0]));//将v[begin(), end())区间中的元素拷贝给本身
    vector<int> v4(v1);//拷贝构造函数,拿另一个vector对象初始化本身
    printvector(v1);
    printvector(v2);
    printvector(v3);
    printvector(v4);
    return 0;
}

在这里插入图片描述

②特性操作

函数原型解释
size_t max_size() const;返回容器的最大长度
size_t capacity() const;返回容器的容量。
size_t size() const;返回容器的实际大小(已使用的空间)。
bool empty() const;判断容器是否为空。
void clear();清空容器。
void reserve(size_t size);容器预留size个元素长度,预留位置不初始化,元素不可访问,作用:预开辟空间,避免多次重新分配空间
void shrink_to_fit();将容器的容量降到实际大小(需要重新分配内存)。
void resize(size_t size);把容器的实际大小置为size,如果size<实际大小,会截断多出的部分;如果size>实际大小,则以默认值0填充新位置
void resize(size_t size,const T &value);把容器的实际大小置为size,如果size<实际大小,会截断多出的部分;如果size>实际大小,就用value填充。

实例:reserve和resize辨析:

#include <iostream> 
#include<vector> 
using namespace std;
void printVector(const vector<int>& vec)//形参使用const,避免被修改
{   //const_iterator只读迭代器
	for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
	{
		cout << *it;
	}
	cout << endl;
}
void test()
{
    //1.resize开辟空间,并初始化
	//2.reserve开辟空间,但不初始化

	vector<int> v2;
	v2.push_back(1);//尾部插入一个元素
	v2.push_back(2);
	v2.push_back(3);

	cout << "size:" << v2.size() << endl;
	v2.resize(5);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
	cout << "size:" << v2.size() << endl;
	printvector(v2);
	v2.resize(2);//如果容器变短,则末尾超出容器长度的元素被删除。
	cout << "size:" << v2.size() << endl;
	printvector(v2);
	v2.resize(5,6);//如果容器变长,也可以用value填充
	cout << "size:" << v2.size() << endl;
	printvector(v2);

	v2.reserve(20);
	v2.push_back(20);
	printvector(v2);//容器变长了,但并没有初始化
	cout << "size:" << v2.size() << endl;
	cout << "capacity:" << v2.capacity() << endl;

	//cout << v2[10] << endl;//err,不能访问未初始化的空间
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

reserve作用:预开辟空间,避免多次重新分配空间
如果不加reserve预开辟空间,我们看看会重新分配多少次空间。

#include <iostream> 
#include<vector> 
using namespace std;
void test()
{
    vector<int> v;
	int* p = NULL;
	int num = 0;

	for (int i = 0; i < 10001000; i++)
	{
		v.push_back(i);
		if (p != &v[0])
		{
			p = &v[0];
			num++;
		}
	}
	cout << "num=" << num << endl;
	return 0;
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述
加上v.reserve(10001000);
在这里插入图片描述

③元素操作

函数原型解释
T &operator[](size_t n);通过[]访问元素,如果越界,不抛异常,程序直接挂掉
T &at(size_t n);通过at方法获取下标为n的元素,如果n越界,抛出out_of_range异常
T *data();返回容器中动态数组的首地址。
const T *data() const;返回容器中动态数组的首地址。
T &front();返回第一个元素。
T &back();返回,最后一个元素。

④赋值操作

作用:通过重载赋值运算符operator=和成员函数assign(),给已存在的容器赋值,将覆盖容器中原有的内容。

函数原型解释
vector &operator=(const vector &v);把容器v赋值给当前容器。
assign(beg, end);将[beg, end)区间中的数据拷贝赋值给本身。
void assign(const size_t n, const T& value); ;将n个value拷贝赋值给本身。
void assign(const size_t n, const T& value);把n个value给容器赋值。

⑤交换操作

💬表格一览:

函数原型解释
void swap(vector &v);把当前容器与v交换。交换的是动态数组的地址。作品:收缩内存空间。

swap妙用:收缩内存空间

#include <iostream> 
#include<vector> 
using namespace std;
void test()
{
    vector<int> v;
	for (int i = 0; i < 100000; i++)
	{
		v.push_back(i);
	}

	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的实际大小:" << v.size() << endl;
	cout << "----------------" << endl;

	v.resize(10);//将容器的实际大小设置为10,但容量没变
	cout << "resize后v的容量:" << v.capacity() << endl;
	cout << "resize后v的实际大小:" << v.size() << endl;
	cout << "----------------" << endl;

	vector<int>(v).swap(v);//匿名对象和v对象交换
	//匿名对象调用拷贝构造,匿名对象的容量和实际大小均为10,此时在与v进行交换,做到了收缩内存的目的
	cout << "与匿名对象交换后v的容量:" << v.capacity() << endl;
	cout << "与匿名对象交换后v的实际大小:" << v.size() << endl;
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

⑥比较操作

💬表格一览:

函数原型解释
bool operator == (const vector< T > & v) const;
bool operator != (const vector< T > & v) const;

⑦插入和删除操作

💬表格一览:

函数原型解释
iterator insert(iterator pos, const T& ele);在指定位置插入一个元素ele 返回指向插入元素的迭代器。
iterator insert(const_iterator pos, int count,ele);迭代器指向位置pos插入count个元素ele.返回指向插入元素的迭代器。
void push_back(const T& ele);尾部插入元素ele
void pop_back();删除最后一个元素
iterator erase(const_iterator start, const_iterator end);删除迭代器从start到end之间的元素,返回下一个有效的迭代器。
iterator erase(const_iterator pos);删除迭代器指向的元素,返回下一个有效的迭代器。

实例:vector插入和删除操作

#include <iostream> 
#include<vector> 
using namespace std;
void printVector(const vector<int>& vec)//形参使用const,避免被修改
{   //const_iterator只读迭代器
	for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
	{
		cout << *it;
	}
	cout << endl;
}
void test()
{
    vector<int> v;
	for (int i = 0; i < 5; i++)
	{
		v.push_back(i + 1);//尾部插入元素
	}

	printVector(v);//1 2 3 4 5

	v.insert(v.begin() + 1, 2, 100);//在第二个元素前插入2个100
	printVector(v);//1 100 100 2 3 4 5

	v.pop_back();//尾部删除一个元素
	printVector(v);//1 100 100 2 3 4
	cout << "-------------" << endl;
	v.erase(v.begin());//删除第一个元素
	printVector(v);//100 100 2 3 4

	vector<int>::const_iterator it=v.erase(v.begin() + 1, v.end() - 1);//删除从第二个元素到倒数第二个元素,返回下一个有效迭代器
	printVector(v);//100 4

	v.insert(it, 66);
	printVector(v);//100 66 4
}
int main()
{
    test();
	return 0;
}

在这里插入图片描述

  • 35
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 44
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿标de杂货铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值