vector的使用

前言

前两期我们对STL和string的使用进行了介绍并对string进行了模拟实现!本期我们接着来对STL的vector进行学习!

本期内容介绍

什么是vector?

vector常用的接口

什么是vector?

通过官方文档可以很清楚的看到,vector是一个可变长的顺序表!这就意味着它可以支持扩容等一系列操作!而且他是个类模板,这就意味着不和数组一样只可以存内置类型,而自定义类型也可以!!!!后面那个是内存池,暂时不管也用不到,后面会介绍~!

vector常用接口的介绍

在正式介绍前我先来介绍一下他类型的重命名!

目前就是这两个在使用时有问题!第一个是实例化参数的类型,第二个size_type就是size_t

这样干说好像没什么卵用,下面遇到例子我会专门指出的!!!

构造、拷贝构造、赋值拷贝、析构

vector<int> v;//默认构造,val不指定默认是0

vector<int> v1(10);//用n个val构造, val不指定默认是0

vector<int> v2(v1.begin() + 2, v1.end());//用迭代器区间构造

vector<int> v3(v2);//拷贝构造

注意:vector<T> v(size_t n, value_type& val)这里的 value_type& val就是T的类型的引用,如果T是内置类型未指定的话默认用其对应的0值给val引用,然后用val去构造,如果指定了指定的值被val引用,用val去初始话!如果T是自定义类型,未指定会去调用该类型的默认构造然后用该类型的引用接收,最后再利用这个引用去做赋值; 如果指定了val直接就是那个自定类型对象的别名,用val去构造!

举个例子:vector<int> v(5);不指定初始化的值,val就是0的别名,直接用5个0构造!

vector<string> v1(10, "hello'');这里是自定义类型,指定了val就是"hello"的别名,用10个val去构造;vector<string> v5(5, string("hello world"));这样也是一样的!!!

再来举个字符串的例子:

结合上面的二维数组就可以这样定义:
vector<vector<int>> vv;

可以这样来初始化二维数组:vector<vector<int>> vv(3,vector<int>(5, 1));或者

vector<vector<int>> vv(3,{1,2,3});  (这里不明白的请点击这里)!

赋值拷贝用起来很简单!就是一个对象给另一个对象赋值的!

vector<int> v1(5, 1);

vector<int> v2(10);

v2 = v1;//赋值拷贝

析构不在多比比了,清理资源释放空间~!自动调用~!

迭代器

OK这里只介绍前面的正向和反向后面C++11新增的和上面的一样不在具体介绍~!

正向

vector<int> v1(5, 2);
vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;

const vector<int> v2(5, 6);
vector<int>::const_iterator cit = v2.begin();
while (cit != v2.end())
{
	cout << *cit << " ";
	++cit;
}
cout << endl;

支持迭代器必然支持范围for,我们上一期 刚调试看完汇编他就是傻瓜式的替换迭代器:

反向

vector<int> v1 = { 1,2,3,4,5 };
vector<int>::reverse_iterator it = v1.rbegin();
while (it != v1.rend())
{
	cout << *it << " ";
	++it;
}
cout << endl;

const vector<int> v2 = { 1,2,3,4,5,6,7,8 };
vector<int>::const_reverse_iterator cit = v2.rbegin();
while (cit != v2.rend())
{
	cout << *cit << " ";
	++cit;
}
cout << endl;

const和非const的区别主要还是权限的问题~!如果不修改建议使用const的!!!

注意:这里的迭代器需要指定类域的原因是模板的原因,模板参数不一样就是一个类,为了让迭代器用法统且不冲突,需要指定是哪个类的迭代器~!

容量相关

OK,我们还是一个一个的来看:

size
vector<int> v(10, 1);
cout << v.size() << endl;

resize

还是分为三种:

n < size,保留前n个,后面的都删掉(不缩容)

size < n < caapcity,尾插元素到n,如果指定了val就用指定的,否则用默认的

n > capacity,扩容到n再尾插

vector<int> v(10, 1);
for (auto e : v)
{
	cout << e << " ";
}
cout << endl;
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

v.resize(5);//n < size,尾删保留前n个
for (auto e : v)
{
	cout << e << " ";
}
cout << endl;
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

v.resize(7, 3);// size < n < capacity,尾插
for (auto e : v)
{
	cout << e << " ";
}
cout << endl;
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

v.resize(20, 5);//n > capacity,扩容+尾插
for (auto e : v)
{
	cout << e << " ";
}
cout << endl;
cout << v.size() << endl;
cout << v.capacity() << endl;

capacity

容量上面刚刚看了,,这里不在演示!

empty

reserve

这个和在string介绍的一样!如果n大于capacity时才会扩容!其他情况不做处理, 也就是这个函数不会缩容!

vector<int> v(10, 1);
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

v.reserve(20);
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

v.reserve(2);
cout << v.size() << endl;
cout << v.capacity() << endl;

OK,我们也可以来验证一下扩容:

vector<int> v;
size_t end = v.capacity();
cout << end << endl;
for (size_t i = 0; i < 100; i++)
{
	v.push_back(i);
	if (end != v.capacity())
	{
		end = v.capacity();
		cout << end << endl;
	}
}

VS下是1.5倍扩!

Linux下是2倍扩:

这里还是和上期介绍的一样,如果提前知道要多少空间的话,我们可以提前开好!这样可以减少扩容的消耗!

shrink_to_fit

这个函数就是为了缩容而准备的!但是不是说你想缩到多少就多少,而是把容量缩小到size

vector<int> v = { 1,3,5,6,2,3,7 };
cout << v.size() << endl;
cout << v.capacity() << endl << endl;
	
v.reserve(100);
cout << v.size() << endl;
cout << v.capacity() << endl << endl;

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

元素访问

operator[]

有const和非const版本,还是权限问题~!非const可以修改,const不可修改~!

at的作用和operator的作用一样,这里不在演示~!

front

back

data

这个函数是返回在顺序表中的第一个元素的指针!

这个接口是C++11提供的,但是C++兼容C语言,你可以直接去取v[0]的地址~!

修改相关

push_back

pop_back

vector<int> v = { 1,2,3,4,5,6,7,8,9 };
for (auto e : v)
{
	cout << e << " ";
}
cout << endl << endl;

v.push_back(0);
for (auto e : v)
{
	cout << e << " ";
}
cout << endl << endl;

v.pop_back();
for (auto e : v)
{
	cout << e << " ";
}
cout << endl;

insert

注意:他这里的position和以前的不一样,以前是个具体的下标!这里是一个迭代器位置!

还有插入一个迭代器区间不是只可以插入当前vector同类型的!而是其他的也是可以的,因为上面也看到了他是一个模板参数!!!

void test_vector7()
{
	vector<int> v(6, 1);

	//在第一个位置插入一个0
	v.insert(v.begin(), 0);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;

	//在4号元素的前面插入5个6
	v.insert(v.begin() + 4, 5,6);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;

	//在2号位置插入一个迭代器区间这
	string s("hello world");
	v.insert(v.begin() + 2, s.begin(), s.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;
}

erase

void test_vector8()
{
	vector<int> v = { 1,2,3,4,5 };
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;

	v.erase(v.begin() + 2);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;

	v.erase(++v.begin(), --v.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl << endl;
}

swap

这个也是交换指针的,不算法库里面的效率高~!

非常成员函数

swap

这里只介绍一个就是全局的swap和string的那个全局的一样,是为了防止用户误操作调到算法库的那个而引起拷贝,所以重载了这个,它的底层是成员函数swap实现的~!

OK,vector的常用接口就介绍到这里,好兄弟我们下期再见!!

结束语: 纵有疾风起,人生不言弃!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值