目录
迭代器的分类
List容器
编辑
总结
在Vector容器中我们学习了迭代器,知道了迭代器的作用和使用方法,本期我们将进一步学习迭代器的概念以及list容器的使用。
迭代器的分类
以算法库中的两个算法为例:
sort算法是用来排序的,reverse算法是用来进行容器的逆置,但是们发现了两个类似迭代器Iterator的东西,但是又与我们之前看到的迭代器不相同,那么这两个迭代器究竟是什么呢?下来为大家一一介绍。
声明:所有迭代器都是模板类型,所以站在语法层面,所有的迭代器变量都可以作为实参传给迭代器类型,但是在使用的角度这是行不通的,什么类型的迭代器,就应该传什么类型的迭代器变量。
1.只读/只写迭代器(output_iterator/input_iterator)
这种迭代器并没有实际对应的类型,我们可以认为,这种迭代器是最基本的类型,其它所有的迭代器都是从此迭代器衍生出来的。
2.单向迭代器(forward_iterator)
单向迭代器,其实就只能进行迭代器的++操作,最典型的就是forward_list,unordered_set和unorder_map容器。
3.双向迭代器(bidirectional_iterator)
双向迭代器,其实就是可以进行迭代器的++和--操作,最典型的就是list,map和set容器。
4.随机迭代器(randomaccess_iterator)
随机迭代器,其实就是可以进行迭代器的++,--,+和-操作,最典型的就是deque,vector和string。
其实不难发现,往下的每个迭代器都是对上述每个迭代器功能的补充,这个就像后期我们学习到的继承的概念,子类可以继承父类的属性,也有自己独有的属性。继承中还有一个很重要的概念就是切片,这个内容我们后期会为大家讲解,现在大家只需要记住一个概念即可,子类对象可以传给父类对象,但是父类对象不能传给子类对象。所以整个关系图如下图所示。
所以模板如果是父类,那么父类之后所有的子类对象都可以进行传递,付过模板是子类,那么子类之前的父类是不能进行传递的。
reverse函数需要传递的参数类型应该是双向迭代器,但是由于随机迭代器是它的子类,所以也可以传随机迭代器,我们知道vector是随机迭代器所以用vector容器进行验证;由于单向迭代器是它的父类,所以不能传单向迭代器,我们知道forward_list是单向迭代器,所以我们用forward_list进行验证。
#include<iostream>
using namespace std;
#include<vector>
#include<forward_list>
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int>::iterator it1 = v1.begin();
while (it1 != v1.end())
{
cout << *it1 ;
it1++;
}
cout << endl;
reverse(v1.begin(), v1.end());
vector<int>::iterator it2 = v1.begin();
while (it2 != v1.end())
{
cout << *it2 ;
it2++;
}
forward_list<int> l1;
l1.push_front(1);
l1.push_front(2);
l1.push_front(3);
l1.push_front(4);
forward_list<int> ::iterator it3 = l1.begin();
while (it3 != l1.end())
{
cout << *it3;
it3++;
}
cout << endl;
reverse(l1.begin(), l1.end());
forward_list<int>::iterator it4 = l1.begin();
while (it4 != l1.end())
{
cout << *it4;
it4++;
}
return 0;
}
我们发现,vector容器的元素进行了逆置,也证明了子类可以传给父类。
我们发现,forward_list容器的元素没有进行逆置, 也证明了父类不能传给子类。
以上便是迭代器分类的所有内容。
List容器
list容器是一个带头双向循环链表。
构造函数
构造函数大家只需要记住,list容器的空间是从空间配置器中申请的,至于空间配置器是什么,这个后期会为大家讲述。list同样可以使用迭代器区间进行构造,但是最有用的就是可以是一个空构造,因为本身已经有了缺省值。
析构函数
修改函数
大部分的函数功能与vector容器类似,大家可以查看vector那一章节。但是要注意的是list中没有reserve功能,也就是没有扩容功能,因为list是链表链表的空间是用多少申请多少,不像vector数组,是不管是否使用直接申请一大块空间。
迭代器
迭代器的使用也与vector类似,大家可以参考vector的使用。
其实大家不妨仔细思考一下,这个begin和rebegin究竟有什么关系呢?
其实只要是双向迭代器或者是双向迭代器的子类都有这个功能,单向迭代器即双向迭代器的父类是没有这个功能的。
单向迭代器,forward_list容器的迭代器如下图。
随机迭代器,vector容器的迭代器如下图。
查看文档之后,确实是这样的,究竟是为什么呢?
其实我们一开始就已经讲述了这个问题的答案,因为单向迭代器是不支持--操作的,双向迭代器和随机迭代器是支持--操作的,所谓的rebegin其实就是把正向迭代器的end作为了begin然后进行--,又把--封装成了++。但是单向迭代器是没有--操作的,所以不支持反向迭代器。
总的来说,stl库底层会对每个容器的功能进行封装,最后形成用户层看着类似的接口,所以只要学习了一个容器的接口之后,学习其它的容器的接口不过是照猫画虎,很容易上手。
总结
本期的内容主要讲解了迭代器的分类和list的基本使用,主要是迭代器的分类,总共分为四类,只读只写迭代器,单向迭代器,双向迭代器,随机迭代器。大家其实只需要记得它们的父子关系即可,在今后遇到模板传参的问题时,记住一句话“子类可以传给父类,但是父类不能传给子类”。list的基本操作其实和vector很相似,因为它们的接口都进行了封装,list的重点是下期我们要学习模拟实现。
本期内容到此结束^_^