理解迭代器对于理解STL框架并掌握STL的使用至关重要。简单地说,迭代器是面向对象版本的指针,STL算法利用迭代器对存储在容器中的元素序列进行遍历,迭代器提供了访问容器和序列中每个元素的方法。

虽然指针也是一种迭代器,但迭代器却不仅仅是指针。指针可以指向内存中的一个地址,通过这个地址就可以访问相应的地址。而迭代器更为抽象,它可以指向容器中的一个位置,我们也许不必关心这个位置的真正物理地址,但是我们可以通过迭代器访问这个位置的元素。

迭代器是算法和容器的“中间人”,遍历链表需要指针,对数组元素进行排序要通过下标来访问数组元素。那么,指针和下标运算符便充当了算法和数据结构的“中间人”;在STL中,容器是封装起来的类模板,其内部结构无从知晓,我们只能通过容器接口来使用容器,但是STL中的算法是通用的函数模板,并不专门针对那一个容器类型。这时请想一想:算法要适用于多种容器,而每一种容器存放的元素又可以是任何类型,如何用普通的指针或下标类充当中介呢?使用指针需要直到其指向的元素类型,使用下标需要在相应的容器中定义过下标操作符,但不是每个容器中都有下标操作符的。这时就必须使用更为抽象的指针--迭代器。

就像我们声明指针时要说明其指向的元素一样,STL的每一个容器类模板中,都定义了一组对应的迭代器类。使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。

1、迭代器的类型

为了满足某些特定算法的需要,STL迭代器主要包括5种基本迭代器类别:输入、输出、前向、双向和随机访问,以及两种迭代器适配器:逆向迭代器适配器和插入迭代器适配器。

1)迭代器分类

输入迭代器对象可以用来从序列中读取数据,但是不一定能够向其中写入数据。输出迭代器具有刚好相反的功能,它允许向序列中写入数据,但是并不保证可以从其中读取数据。

前向迭代器既是输入迭代器又是输出迭代器,因此它即支持数据读取,也支持数据写入,并且可以对序列进行单向的遍历。

双向迭代器的功能与前向迭代器相似,不同之处在于,双向迭代器在两个方向上都可以对数据遍历。也就是说,双向迭代器必须支持前向迭代器的所有操作,此外,还必须支持双向操作,从而使对序列进行反向遍历。

随机访问迭代器也是双向迭代器,它对迭代器提供了更高的要求,能够在序列中的任意两个位置之间进行跳转。

2、迭代器适配器

适配器是用来修饰或调整其他类接口的,迭代器适配器便是用来扩展(或调整)迭代器功能的类。当然这样的适配器本身也称为迭代器,只是这种迭代器是通过改变另一个迭代器而得到的。STL中定义了两类迭代器适配器:

逆向迭代器是一种适配器,它通过重新定义递增运算和递减运算,使其行为正好倒置。这样,使用这类迭代器,算法将以逆向次序处理元素。所有标准容器都允许使用逆向迭代器来遍历元素。

插入型迭代器用来将赋值操作转换为插入操作。通过这种迭代器,算法可以执行插入行为而不是覆盖行为。c++标准程序库提供了3种插入型迭代器:后插入型迭代器、前插入型迭代器、普通插入型迭代器。

例子:

应用逆向迭代器和后插迭代器来操作向量容器中的元素

#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>
using namespace std;
int main()
{
 int A[] = {1,2,3,4,5};
 const int N = sizeof(A) / sizeof(int);
 vector<int> col1(A,A+N);
 ostream_iterator<int>output(cout," ");
 cout << "List col1 contains:";
 copy(col1.begin(),col1.end(),output);
 
 vector<int>::iterator pos = col1.begin();//定义指向初始元素的迭代器
 cout << "\nThe first element is:" << *pos;//输出第一个元素
 vector<int>::reverse_iterator rpos = col1.rbegin();//应用逆向迭代器指向最后一个元素
 cout << "\nThe last element is:" << *rpos << endl;//输出最后一个元素
 back_insert_iterator<vector<int>>iter(col1);//声明后插迭代器
 *iter = 66;//应用后插迭代器插入元素66
 back_inserter(col1) = 88;//应用函数后插入元素88
 copy(col1.begin(), col1.end(), output);//输出后插操作后的向量容器col1中的元素
 getchar();
 getchar();
 cout << endl;
}

2、迭代器相关的辅助函数

advance()、distance()两个提供了所有迭代器一些原本只有随机访问迭代器才有的访问能力:前进或后退多少个元素,以及处理迭代器之间的距离。iter_swap()函数允许用户交换两个迭代器的值。

void advance(InputIterator& pos,Dist n);

该函数使输入型迭代器前进(或后退)n个元素,对于双向或随机访问迭代器,可以取负值,表示向后访问。

dist distance(InputIterator pos1,InputIterator pos2);

该函数传回两个输入迭代器pos1和pos2之间的距离,两个迭代器必须指向同一个容器。如果不是随机访问迭代器,则从pos1开始往前走必须能够到达pos2,即pos2的位置必须与pos1相同或在后。

iter_swap()可以交换两个迭代器所指向的元素值。

void iter_swap(ForwardIterator1 pos1,ForwardIterator2 pos2);

该函数用于交换迭代器pos1和pos2所指向的元素值,迭代器的类型不必相同,但所只元素之间必须可以相互赋值。

#include<iostream>

#include<iterator>

#include<list>

#include<algorithm>

using namespace std;

int main() {

int A[] = {1,2,3,4,5};

const int N = sizeof(A) / sizeof(int);

list<int> col1(A, A + N);

ostream_iterator<int> output(cout," ");

cout << "List col1 contains:";

copy(col1.begin(),col1.end(),output);//输出初始列表容器col1中的元素

list<int>::iterator pos = col1.begin();//定义指向初始元素的迭代器

cout << "\nThe first element is:" << *pos;//输出第一个元素

advance(pos,3);//前进3个元素,指向第四个元素

cout << "\nThe 4th element is:" << *pos;//输出第4个元素

cout << "\nThe advanced distance is:" << distance(col1.begin(),pos);//输出当前迭代器位置与初始位置的距离

iter_swap(col1.begin(),--col1.end());//交换列表容器中第一个元素和最后一个元素

cout << "\nAfter exchange list col1 constains:";  copy(col1.begin(),col1.end(),output);//输出交换元素后列表容器col1中的元素

getchar();  getchar();

cout << endl;

}

8、泛型程序设计与c++标准模板库3.迭代器的更多相关文章

  1. 8、泛型程序设计与c++标准模板库1、泛型程序设计的概念和术语

    有效地利用已有的成果,将经典的.优秀的算法标准化.模块化,从而提高软件的生产率,是软件产业化的需求,为了实现这一需求,不仅需要面向对象设计思想,而且需要泛型程序设计思想. c++语言提供的标准模板库( ...

  2. 8、泛型程序设计与c++标准模板库4.标准c++库中的算法

    标准c++算法是通过迭代器和模板来实现的,其实算法本身就是一种函数模板. 算法从迭代器那里获得一个元素,而迭代器则知道一个元素在容器中的什么位置.迭代器查找元素的位置并将这些信息提供给算法以便算法能够 ...

  3. 8、泛型程序设计与c++标准模板库2、c++标准模板库中的容器

    顺序容器类以逻辑线性排列方式存储元素,在这些容器类型中的元素在逻辑上被认为是连续的存储空间中存储的.顺序容器可用于存储线性群体. 在关联容器类中,元素的存储和检索基于关键字和元素与其他元素之间的关系, ...

  4. C++学习笔记53:泛型程序设计与C++标准模板库

    泛型程序设计的基本概念 编写不依赖于具体数据类型的程序 将算法从特定的数据结构中抽象出来,成为通用的 C++模板为泛型编程程序设计奠定了关键的基础 模型:符合一个概念的数据类型称为该概念的模型,例如: ...

  5. 8、泛型程序设计与c++标准模板库2.5容器适配器

    容器适配器是用来扩展7中基本容器的,是修改和调整其他类接口的类.他们不提供存放数据的实际数据结构的实现方法,而且容器适配器也不支持迭代器. 1.标准栈容器 使用STL中的标准栈为程序员提供了一层附加的 ...

  6. 8、泛型程序设计与c++标准模板库5.函数对象

    1.函数对象 函数对象是STL提供的第四类主要组件,它使得STL的应用更加灵活方便,从而增强了算法的通用性.大多数STL算法可以用一个函数对象作为参数.所谓“函数对象”其实就是一个行为类似函数的对象, ...

  7. 8、泛型程序设计与c++标准模板库2.3双端队列容器

    双端队列容器是一种放松了访问权限的队列.除了从队列的首部和尾部访问元素外,标准的双端队列也支持通过使用下标操作符"[]"进行直接访问. 它提供了直接访问和顺序访问方法.其头文件为& ...

  8. 8、泛型程序设计与c++标准模板库2.2向量容器

    向量容器属于顺序容器,用于容纳不定长线性序列(即线性群体),提供对序列的快速随机访问(也称直接访问).这一点与c++语言支持的基本数组类型相同,但基本数据类型不是面向对象的.而面向对象的向量是动态结构 ...

  9. 第十章 泛型程序设计与C++标准模板库 泛型程序设计及STL的结构

随机推荐

  1. HBase常用操作-HBaseUtil

    package com.zhen.hbase; import java.io.IOException; import java.util.ArrayList; import java.util.Col ...

  2. python循环切片

    x = [0,99, 'a', 1, 2, 'b',5, 3, 0,'a' ,1, 8, 5,'b',5,9,5] b=[] c=[] d=[] for i in range(len(x)): if ...

  3. 关于C++类的成员函数是否要加关键字“const”

    原则:类的成员函数在小括号后大括号前加上 const ,代表不准备改变对象的数据.不加的话代表有可能会改变对象的数据. 1.当常量对象,就是加上const修饰的类的成员去调用常量成员函数时,这表示:对 ...

  4. CSS控制表格嵌套

    网页设计应用中,当我们不能完全放弃表格的使用时,为了达到预期的效果,不免要用到表格嵌套(特别是多层嵌套)方式来进行布局.可能很多同仁都遇到过这样的问题,为了达到显示效果要为每一个(每一层)的表格写不同 ...

  5. php设计模式课程---2、为什么会用到简单工厂设计模式

    php设计模式课程---2.为什么会用到简单工厂设计模式 一.总结 一句话总结: 比如调用数据库的语句,如果调用的数据库名字改了,或者调用的数据库类型改了(比如从Mysql用到了Mysqli),那么要 ...

  6. io.js的六大新特性

    io.js是nodejs的友好版的分支("friendly fork”).它支持npm中所有的同样模块,且使用了v8最新版本的截取(v8是被node.js使用js解释器),且修复了很多的bu ...

  7. 如何生成HLS协议的M3U8文件

    什么是HLS协议: HLS(Http Live Streaming)是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件 ...

  8. BZOJ3812 清华集训2014 主旋律

    直接求出强联通生成子图的数量较难,不妨用所有生成子图的数量减去非强联通的. 非强联通生成子图在所点后满足编号最小的点所在的强联通分量不是全集. 由于$n$很小,我们可以考虑状态压缩. 对于点集$S$, ...

  9. 省选/NOI刷题Day2

    bzoj2616 放一个车的时候相当于剪掉棋盘的一行,于是就可以转移了,中间状态转移dp套dp,推一下即可 bzoj2878 环套树期望dp 手推一下递推式即可 bzoj3295 树状数组套权值线段树 ...

  10. bzoj 4034: 树上操作 线段树

    题目: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...