STL之vector

写在前面

标准库类型vector表示对象的集合, 其中所有对象的类型都相同. 集合中的每个对象都有一个与之对应的索引, 索引用于访问对象.

因为vector "容纳着"其他对象, 所以它也被称为容器.

使用vector需要导入vector头文件:

include <vector>
using namaspace std;

构造

语法形式:
vector 变量名; //T为数组中元素的类型

一些常见的构造如下:

vector<int> vec;	//初始化一个大小, 容量均为0的vector对象
vector<string> sVec;	//可为其他类型
vector<diyType> xVec;	//甚至自定义类型
	//列表初始化
	vector<int> nVec = { 1, 2, 3 };
	vector<string> sVec{ "1", "12", "123" };
	vector<int> nVec2(initializer_list<int>{1, 2, 3});	//C++11标准提供的

	//带参构造
	vector<int> nVec3(10, 1);	//构造一个大小为10, 容量为10, 各元素初始值为1的vector对象, 一般用于希望初始化后可直接使用下标访问的常见
	vector<int>::size_type nVec2Size = nVec2.size();
	vector<int>::size_type nVec2Capacity = nVec2.capacity();

	vector<int> nVec4(nVec3);	//拷贝构造, 注意两个vector对象的类型必须一致.
	vector<int> nVec5 = nVec4;	//赋值构造, 注意两个vector对象的类型必须一致.

初始化列表initializer_list可参考:初始化列表

size_type类型

同string一样, 暂无法得知其具体细节, 但可知它是一个无符号类型.

使用时需要注意, 应习惯性的声明当前类型对应的size_type对象.

vector<int> nVec{1, 2, 3};
vector<int>::size_type nSize = nVec.size();

//虽然可以但不建议这样
vector<string> sVec(1, "1");
vector<int>::size_type nSize = sVec.size();

容器大小容量

size成员函数

size成员函数返回容器中的元素数量.

函数原型:
size_type size() const;

vector<int> nVec{1, 2, 3};
vector<int>::size_type nSize = nVec.size();	//size = 3

empty成员函数

判断容器是否为空, 为空返回true, 否则返回false。

//函数原型
bool empty() const;

vector<string > sVec;
if ( sVec.empty() )
{
	//容器为空
}

capacity成员函数

返回当前容器容量, 即在不分配更多的存储的情况下容器可以包含的元素数。

注意: size会小于等于capacity.

//函数原型
size_type capacity() const;

vector<int> nVec(10, 0);	//初始size为10, 初始容量为10
vector<int>::size_type nCap = nVec.capacity();

resize成员函数

为容器指定新的大小。

//函数原型
//new_size: 新指定的容器大小
//value: 新size大于旧size时添加到容器的新元素的初始化值。 如果省略该值,则新对象(类型为Type)将使用其默认构造函数。
void resize(size_type new_size);
void resize(size_type new_size, Type value);

注意:

  1. 当新size 等于 旧size时, 这里不执行任何操作
  2. 当新size 大于 旧size时, 会向容器中添加新元素(初始值如上描述)至新size大小, 如果新size超出当前容量, 会动态扩容, 内存地址会变更
  3. 当新size 小于 旧size时, resize 将删除最接近容器末尾的元素,直到达到新size为止。
vector<int> nVec = { 1, 2, 3 };
vector<int>::size_type nVecSize = nVec.size();
vector<int>::size_type nVecCapacity = nVec.capacity();

cout << "初始状态, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;

nVec.resize(5, 666);
nVecSize = nVec.size();
nVecCapacity = nVec.capacity();

cout << "新size > 旧size, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;

nVec.resize(1, 666);
nVecSize = nVec.size();
nVecCapacity = nVec.capacity();
cout << "新size < 旧size, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;

resize测试

reserve成员函数

为容器保留最小的容量,必要时为其分配空间。

//函数原型
void reserve(size_type count);

vector<int> nVec2(initializer_list<int>{1, 2, 3});	//C++11标准提供的初始化列表
vector<int>::size_type nVec2Size = nVec2.size();
vector<int>::size_type nVec2Capacity = nVec2.capacity();
cout << "reserve前初始状态, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;

nVec2.reserve(5);
nVec2Size = nVec2.size();
nVec2Capacity = nVec2.capacity();
cout << "reserve 新容量 > 旧容量, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;

nVec2.reserve(1);
nVec2Size = nVec2.size();
nVec2Capacity = nVec2.capacity();
cout << "reserve 新容量 < 旧容量 且 新容量 < 当前size, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;

reserve测试
还需注意的是使用reserve预留容量后, 并不代表size也会变为该大小.

vector<int> nVec;		//初始化一个size 为0, 容量为0 的vector对象
nVec.reserve(10);		//预留10个int大小的内存, 此时容量为10, 但size依旧为0
nVec[5] = 0;			//错误: 非法下标访问

nVec.resize(10, 666);
nVec[5] = 0;			//正确: 此时0 - 9均为合法下标

小结

resize和reserve成员函数指定的新大小或新容量在大于当前最大容量时, 都会动态扩容, 并未另外找一块更大的内存并将所有元素拷贝到新内存中后, 删除原来小的内存.

赋值操作

vector提供三种赋值操作, 需注意赋值对象类型应该一致.

vector<int> nVec{1, 2, 3};

//assign成员函数

vector<int> nVec2;
nVec2.assign(nVec.begin(), nVec.end());

//等号运算符
vector<int> nVec3;
nVec3 = nVec;

//swap成员函数: 交换两个vector对象中的元素
vector<int> nVec4;
nVec4.swap(nVec);	//交换过后, nVec4的size为3, 容量为3, 而nVec的size为0, 容量为0

访问操作

vector<int> nVec{1, 2, 3};

//使用at成员函数访问容器元素
//注意: 如果下标非法, 则引发异常。
int nNum = nVec.at(1);	//返回2

//使用下标运算符, 下标非法, 则引发异常
int nNum2 = nVec[1];	//返回2

//front, back成员函数
int nFrontNum = nVec.front();	//返回1
int nBackNum = nVec.back();		//返回3

遍历vector对象中元素:

vector<int> nVec{1, 2, 3, 4, 5};

//for语句遍历: 保证下标合法性
for (vector<int>::size_type i = 0; i < nVec.size(); i++)
{
	cout << nVec[i] << endl;
}

//C++11新标准提供范围for语句
for (auto n : nVec)
{
	cout << n << endl;
}

//使用迭代器遍历
for (auto it = nVec.begin(); it != nVec.end(); it++)
{
	cout << *it << endl;
}

for (vector<int>::iterator it = nVec.begin(); it != nVec.end(); it++)
{
	cout << *it << endl;
}

插入操作

insert成员函数

在指定位置添加指定数量的指定元素.

函数原型:

iterator insert(
    const_iterator position,
    const Type& value);

iterator insert(
    const_iterator position,
    Type&& value);

void insert(
    const_iterator position,
    size_type count,
    const Type& value);

template <class InputIterator>
void insert(
    const_iterator position,
    InputIterator first,
    InputIterator last);

//参数解析    
//position: 向量中插入第一个元素的位置。
//value: 插入到向量中的元素的值。
//count: 插入向量中的元素数目。
//first: 要复制的范围元素中的第一个元素的位置。
//last: 要复制的元素范围以外的第一个元素的位置。

//返回值: 前两个 insert 函数返回一个指定新元素插入到向量的位置的迭代器。

示例:

vector<int> nVec;
nVec.insert(nVec.begin(), 1);	//nVec[0] = 1;
nVec.insert(nVec.begin(), 2);	//nVec[0] = 2; nVec[0] = 1;
nVec.insert(nVec.begin(), 3, 6);	//nVec = { 6, 6, 6, 2, 1};

vector<int> nVec2;
nVec2.insert(nvec2.begin(), nVec.begin(), nVec.end());	//nVec2 = { 6, 6, 6, 2, 1};

push_back成员函数

在容器末尾处添加一个元素。

函数原型如下:

void push_back(const T& value);
vector<int> nVec;
nVec.push_back(1);
nVec.push_back(2);
nVec.push_back(3);

删除操作

pop_back成员函数

删除容器末尾处的元素。

注意: 不可对空vector对象调用pop_back函数, 否则会引发异常

//函数原型
void pop_back();

vector<int> nVec;
//nVec.pop_back();	//不可对空vector调用pop_back, 会引发异常
nVec.push_back(1);
nVec.push_back(2);
nVec.push_back(3);

nVec.pop_back();	//nVec = { 1, 2 };

erase成员函数

从指定位置删除容器中的一个元素或一系列元素。

//函数原型
iterator erase(
    const_iterator position);

iterator erase(
    const_iterator first,
    const_iterator last);

//position: 要从向量中移除的元素的位置。
//first: 要从向量中移除的第一个元素的位置。
//last: 紧接要从向量中移除的最后一个元素的位置
vector<int> nVec{ 1, 2, 3, 4, 5};
nVec.erase(nVec.begin());	//删除第一个元素, 删除后nVec = { 2, 3, 4, 5}
//nVec.erase(nVec.end());		//错误: nVec.end()指向最后一个元素的后一个位置, 这里会引发异常
nVec.erase(nVec.begin(), nVec.end());	//删除所有元素

vector的动态机制

普通数组在声明时必须指定内存大小, 而vector被称为动态数组, 是因为vector能根据当前的size和容量来动态的扩大或缩小其内存大小.

这里注意动态的内存分配并不是, 而是找一个新的内存空间, 将原有数据拷贝到新内存空间下, 然后释放掉原有内存, 以此来实现动态的特性.

而每次新分配的内存大小为旧内存大小的1.5倍(或2倍).

vector<int> nVec10(10, 1);
cout << "起始状态--vector对象地址: " << &nVec10 << ", 内部元素集合起始地址: " << &nVec10[0] << ", 容量: " << nVec10.capacity() << endl;
	
nVec10.insert(nVec10.begin(),666);	//这里插入操作会动态扩容, 新内存大小为之前的1.5倍
cout << "insert后--vector对象地址: " << &nVec10 << ", 内部元素集合起始地址: " << &nVec10[0] << ", 容量: " << nVec10.capacity() << endl;

动态扩容测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值