前言
前两期我们对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的常用接口就介绍到这里,好兄弟我们下期再见!!
标签:const,cout,val,v1,v2,vector,使用 From: https://blog.csdn.net/m0_75256358/article/details/136758517结束语: 纵有疾风起,人生不言弃!