STL其他内容解析:关于C++中STL的理解和应用
作用:
迭代器(iterator)是一种抽象的设计理念,通过迭代器可以在不了解容器内部原理的情况下遍历容器。
除此之外,STL中迭代器一个最重要的作用就是作为容器(vector,list等)与STL算法的粘结剂,只要容器提供迭代器的接口,同一套算法代码可以利用在完全不同的容器中,这是抽象思想的经典应用。
使用:
vector<int>::iterator it;
vector<int> a;
vector<int> b;
for (it=a.begin(); it<a.end(); it++){
cout<<*it<<" ";
}
for ( it=b.begin(); it<b.end(); it++){
cout<<*it<<" ";
}
容器一般含有其各自的迭代器型别(iterator types),所以当你使用一般的容器迭代器时,并不需要含入专门的头文件。
以下是关于代码的解释:
vector<int>::iterator it;
两个冒号表示作用域操作符。::操作符在其左操作数的作用域内找到其右操作数的名字。
这样就定义了一个迭代器名字为it(名字可以随便取),并且这个迭代器的作用域是vector。
这个迭代器it只是初始化,并未赋值,所以在下面的两个vector a,b都可以用it来遍历,
就像定义了一个循环变量i,可以遍历两个数组a,b道理是一样的。
vector的.begin()和.end()
vector的.begin()和.end()方法都会返回一个vector::iterator对象,分别指向vector的首元素位置和尾元素的下一个位置(我们可以称之为结束标志位)。
*it 迭代器所指向的内容
对一个迭代器的使用与一个指针变量的使用极为相似,或者可以这样说,指针就是一个非常标准的迭代器。
迭代器的相应型别
我们都知道type_traits 可以萃取出类型的型别,根据不同型别可以执行不同的处理流程。那么对于迭代器来说,是否有针对不同特性迭代器的优化方法呢?答案是肯定的。拿一个STL算法库中的distance函数来说,distance函数接受两个迭代器参数,然后计算他们两者之间的距离。显然对于不同的迭代器计算效率差别很大。比如对于vector容器来说,由于内存是连续分配的,因此指针直接相减即可获得两者的距离;而list容器是链式表,内存一般都不是连续分配,因此只能通过一级一级调用next()或其他函数,每调用一次再判断迭代器是否相等来计算距离。vector迭代器计算distance的效率为O(1),而list则为O(n),n为距离的大小。
因此,根据迭代器不同的特性,将迭代器分为5类:
- Input Iterator:这种迭代器所指的对象为只读的。
- Ouput Iterator: 所指对象只能进行一次写入操作。
- Forward Iterator: 允许”读写型”算法在迭代器区间内进行读写操作,比如说replace函数需要读取区间内容,根据所读内容决定是否写入
- Bidirectional Iterator : 可双向移动。某些算法需要反向遍历某个迭代器区间
- Random Access Iterator : 前四种迭代器只提供部分指针算数能力(前三种支持++运算符,后一种还支持–运算符),第五种则支持所有指针的算术运算,包括p + n,p - n,p[n],p1 - p2,p1 < p2
这五种迭代器的继承关系如下所示。
了解了迭代器的类型,我们就能解释vector的迭代器和list迭代器的区别了。显然vector的迭代器具有所有指针算术运算能力,而list由于是双向链表,因此只有双向读写但不能随机访问元素。故vector的迭代器种类为Random Access Iterator,list 的迭代器种类为Bidirectional Iterator。
小结
STL使用迭代器将算法和容器结合,利用迭代器型别可以针对不同迭代器编写更加高效的算法,这里一点很重要的思想就是:利用C++重载机制和参数推导机制将运行期决议问题提前到编译期决议,也就是说,我们不需要在运行时判断迭代器的类型,而是在编译期就已经决定。这很符合C++模板编程的理念。
部分参考:https://blog.csdn.net/wutao1530663/article/details/64922389