欢迎来到博主的专栏——c++编程
博主ID:代码小豪
前言
关于这片博客,由于博主对于STL的6大组件还处于一知半解的阶段,因此,博主会将重点放在vector的使用上,而不会详细的讲解诸如iterator,allocator等作用。
事实上,如果你想懂STL,那么6大组件是你绕不开的一点,但如果你只是想用STL(比如用STL去leetcode刷刷题)。那么只需要和我一起了解他的接口就行了。
vector
vector单词的意思是矢量,向量,但是在STL中vector容器则是一个顺序表的数据结构。可以认为是一个大小自动改变的数组。其模板是
template < class T, class Alloc = allocator<T> > class vector;
我们先从文档当中看一下模板的类型代表什么。
T是vector元素的类型
Alloc则是内存配置器,由于博主没打算细讲内存配置器,因此我们先用其缺省值
STL很细心的为我们提供了内存配置器,因此我们只用它的缺省值也能使用vector
在vector中的成员类型有以下几个
成员类型 | 定义 |
---|---|
value_type | 模板的第一个类型参数,即模板声明中的T |
allocator_type | 模板的第二个类型参数,即vector空间配置器 |
reference | 成员的引用类型,可以理解为value_type& |
difference_type | 代表有符号整型 |
size_type | 代表无符号整型 |
希望大家很记住以上这几种类型,这些类型经常用在vector的成员函数的声明中。
成员函数
构造、析构、与赋值
vector的构造函数被重载成了以下四种形式
default (1)
explicit vector (const allocator_type& alloc = allocator_type());
fill (2)
explicit vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());
range (3)
template <class InputIterator> vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
copy (4)
vector (const vector& x);
看着这些密密麻麻的参数,估计大伙头都大了吧,没关系,我们可以忽略参数alloc,因为这是空间配置器,我们暂时不需要为其传递参数,只使用缺省值就行,因为缺省值传递的是STL里的空间配置器,那是大神为我们编写的(笑)。
我们可以在上述构造分成四类
(1)default构造:default构造指的是在实例化对象时不传递任何参数时调用的构造函数。vector的default构造会实例化一个空的顺序表给我们。
(2)填充构造(fill),在实例化对象的时候填充n个值为val的元素,如果使用val的缺省值,那么会向vector填充n个0。
(3)范围构造(range),在实例化对象的时候传入迭代器,构造一个包含与[first,last)范围内,相同数量元素的容器,每个元素以相同的顺序从该范围内的相应元素构造。
(4)拷贝构造(copy),构造一个与x相同的vectir对象。
使用示例
vector<int> v1;//默认构造
vector<int> v2(4,2);//填充构造
//先为v1插入整型1~10
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
vector<int> v3(v1.begin(),v1.end());//迭代器构造
vector<int> v4(v3);//拷贝构造,构造一个和v3相同元素的vector
析构函数则没有太多需要说明的,因为vector设计的析构函数不需要传入参数,而且当对象生命周期到了以后会自动调用析构,因此不太需要用户在这方面构思太多。
赋值
vector& operator= (const vector& x);
赋值函数并没有重载其他参数,调用赋值函数时,只需要传入要赋值的vector对象即可,operator=会将x的内容传入到容器当中,替换掉原有容器的数据,并且将容器的size修改成符合的数据。
v1 = v2;//operator=
iterator
vectir的迭代器有四种类型,分别为
- iterator,正向迭代器
- const_iterator ,定值正向迭代器
- reverse_iterator ,反向迭代器
- const_reverse_iterator 定值反向迭代器
定值迭代器是不能修改数据的迭代器,而反向迭代器则会从后向前迭代。
vector的接口有8种,实际上掌握四种即可。
iterator begin();
const_iterator begin() const;//begin的重载版本
iterator end();
const_iterator end() const;//end的重载版本
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;//rbegin的重载版本
reverse_iterator rend();
const_reverse_iterator rend() const;//rend的重载版本
如果vector对象不具有常性,那么返回的迭代器则不会是定值迭代器(非const迭代器),若vector对象具有常性,那么返回的迭代器就是定值迭代器(const迭代器)。
既然他们被称为迭代器,那么最具代表的用法就是用迭代器遍历挣个数组了、
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
const vector<int>v2(v1);
//非consr对象的迭代器是非const类型的
vector<int>::iterator itb1=v1.begin();
vector<int>::iterator ite1=v1.end();
while (itb1 != ite1)
{
cout << ++(*itb1) << ' ';
itb1++;
}
cout<<endl;
//const对象的迭代器是const类型的
vector<int>::const_iterator itb2 = v2.begin();
vector<int>::const_iterator ite2 = v2.end();
while (itb2 != ite2)
{
//(*ite2)++;error const_iterator不可被修改
cout << *itb2++ << ' ';
}
cout << endl;
vector<int>::reverse_iterator ritb1 = v1.rbegin();//反向迭代器
vector<int>::reverse_iterator rite1 = v1.rend();
while (ritb1 != rite1)//反向迭代器可以逆序遍历
{
cout << *ritb1++ << ' ';
}
cout << endl;
vector<int>::const_reverse_iterator critb1 = v2.rbegin();
vector<int>::const_reverse_iterator critb2 = v2.rend();
while (critb1 != critb2)
{
cout << *critb1++ << " ";
}
}
capacity
capacity的接口都是用来查看或修改vector当中内存信息,比如当前容量,元素个数。
size_type size() const;//返回vector容器的当前元素个数
size_type capacity() const;//返回vector容器的容量
size()和capacity()是获取vector对象的信息
vector<int> v1;
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
vector<int> v2;
cout << v1.size() << endl;//获取v1当前的元素个数
cout << v2.size() << endl;//获取v2当前的元素个数
cout << v1.capacity() << endl;//获取v1的容量大小
当vector的元素个数超过容量大小时,vector会进行扩容,使扩容后的容量可以容纳当前的元素个数。
当然,我们可以用resize和recapacity对容器进行修改。
void resize (size_type n, value_type val = value_type());//修改元素个数
void reserve (size_type n);//修改容器额容量的大小
resize将vector容器的元素个数变成n个。
如果n小于vector容器的元素个数,那么vector将会保留前n个元素,将剩余元素销毁、
如果n大于vector容器的元素个数,那么会向vector插入val的值,直到vector容器的元素个数变为n。val的值默认是0
如果n的值大于capacity,那么vector容器将会进行扩容,直到vector容器可以容纳n个元素为止
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)//向v1尾插10个元素
{
v1.push_back(i);
}
v1.resize(2);//resize 默认用0填充,也可以指定val的值
//此时v1的元素只剩下前2个元素
recapacity则是对容器的容量进行修改。
如果n大于容器的当前容量,那么vector会进行扩容,将容量变为能容纳n为止,
如果n小于容器的容量,那么不会进行缩容。
recapacity只对容量造成修改,不会对vector的元素个数和元素进行修改。
element access
vector为我们提供了访问元素的接口。
除了operator[],其他的用的并不多,而且作用都是大差不差,因此这里博主就重点说明operator[]就行了。
operator[]是将下标访问符([])重载成函数了,我们在使用数组的时候经常会用到这个符号,其作用是访问某个位置的数组元素。而在vector当中,则是改为用operator[]访问容器元素。
reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
reference是vector中的元素的引用。如果vector的元素是T类型,那么reference则是T&类型。
operator[]会为我们返回vector当中n位置的引用,但是要注意n位置必须是合法的,也就是n不能大于vector的size。
同时我们也要注意vector对象是否具有常性,如果是const修饰vector对象,那么返回的引用则是const T&。反之则是T&。
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);//向v1尾插10个元素
}
for (int i = 0; i < v1.size(); i++)
{
v1[i]++;//用operator =访问元素
cout << v1[i]<<' ';
}
modifier
通过modifier的接口可以对vector对象进行修改。
尾删与尾插
void push_back (const value_type& val);//尾插
void pop_back();//尾删
vector的数据结构是一个顺序表,因此push_back是在顺序表的表尾插入一个元素,而pop_back则是在顺序表的表尾删除一个元素。
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);//向尾部插入数据
}
v1.pop_back();//删除尾部的数据
v1.pop_back();
v1.pop_back();
for (auto& e : v1)
{
cout << e;
}
插入与删除
single element (1)
iterator insert (iterator position, const value_type& val);
fill (2)
void insert (iterator position, size_type n, const value_type& val);
range (3)
template <class InputIterator> void insert (iterator position, InputIterator first, InputIterator last);
插入的函数被重载成了三种,一种在position的位置上插入一个值为val的元素,第二中则是在position上插入n个值为val的元素。
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
vector<int>v2(v1);
v1.insert(v1.begin(), 5);//在表头插入一个5
v2.insert(v2.begin()+3, 5, 6); //在表头的后三个元素的位置插入5个6.
for (auto& e : v1)
{
cout << e<<' ';
}
cout << endl;
for (auto& e : v2)
{
cout << e << ' ';
}
而第三种,insert()传递的参数都是iterator类型或者Inputiterator类型的迭代器。iterator我们熟悉,但是inputiterator却是一个模板的类型参数。这就意味着我们使用insert时需要实例化出模板函数
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
vector<int>v2(v1);
v1.insert(v1.end(), v2.begin(), v2.end());//将v2插入到v1的表头中
for (auto& e : v1)
{
cout << e << ' ';
}
删除erase()
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
删除vector当中position位置的元素,或者删除从first到last范围内的所有元素。
vector<int> v1;//默认构造
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}
vector<int>v2(v1);
v1.erase(v1.begin() + 2);//删除第三个元素,表头元素加2即为表中第三个元素
v2.erase(v2.begin()+5,v2.end());//删除v2第6个及其往后所有元素
for (auto& e : v1)
{
cout << e << ' ';
}
cout << endl;
for (auto& e : v2)
{
cout << e << ' ';
}