技术在于交流、沟通,本文为博主原创文章转载请注明出处并保持作品的完整性

本节主要介绍STL六大部件中的Iterators迭代器.

在语言方面讲,容器是一个class template, 算法是一个仿函数, 分配器class template, 迭代器是一个class template, 适配器class template, 分配器class template

从图中我们可以看出算法是看不到容器的,容器跟算法的交互必要用迭代器做桥梁,那么迭代器是怎样让容器和算法满足各自的需求的呢?

我们先看一下都有哪些迭代器

struct input_iterator_tag{};//write-read迭代器
struct output_iterator_tag{};//read-only输出流
struct forward_iterator_tag : public input_iterator_tag{}//单向迭代器 forward_list multiset/map;
struct bidirectional_iterator_tag : public input_iterator_tag{}//双向迭代器 hash list set map;
struct random_access_iterator_tag : public input_iterator_tag{}//随机迭代器 array vector deque;

类图如下

下面我们验证一下各种容器的迭代器

这是测试代码

#include <iostream>
#include <iterator>
#include <array>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <forward_list>
#include <deque>
#include <unordered_set>
#include <unordered_map> using namespace std; void _display_category(input_iterator_tag)
{
cout << "input_iterator_tag" << endl;
} void _display_category(output_iterator_tag)
{
cout << "output_iterator_tag" << endl;
} void _display_category(forward_iterator_tag)
{
cout << "forward_iterator_tag" << endl;
} void _display_category(bidirectional_iterator_tag)
{
cout << "bidirectional_iterator_tag" << endl;
} void _display_category(random_access_iterator_tag)
{
cout << "random_access_iterator_tag" << endl;
} template<typename I>
void display_ccategory(I iter)
{
typename iterator_traits<I>::iterator_category cagy;
_display_category(cagy);
} int main()
{
display_ccategory(array<int, >::iterator());
display_ccategory(vector<int>::iterator());
display_ccategory(list<int>::iterator());
display_ccategory(forward_list<int>::iterator());
display_ccategory(deque<int>::iterator());
cout << endl;
display_ccategory(set<int>::iterator());
display_ccategory(multiset<int>::iterator());
display_ccategory(map<int,int>::iterator());
display_ccategory(multimap<int,int>::iterator());
cout << endl;
display_ccategory(unordered_set<int>::iterator());
display_ccategory(unordered_multiset<int>::iterator());
display_ccategory(unordered_map<int,int>::iterator());
display_ccategory(unordered_multimap<int,int>::iterator()); return ;
}

迭代器是怎样让容器和算法满足各自的需求的呢

template<typename _Iterator, typename _Container>
class __normal_iterator
{
protected:
_Iterator _M_current; typedef iterator_traits<_Iterator> __traits_type; public:
typedef _Iterator iterator_type;
typedef typename __traits_type::iterator_category iterator_category;
typedef typename __traits_type::value_type value_type;
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::reference reference;
typedef typename __traits_type::pointer pointer;
...
}

iterator_category,表示迭代器的分类(上面的5中类型)

value_type,表示你的value类型(vecotr<int>,此时的value_type就是int)

difference_type,表示两个迭代器指针间的距离(如begin()和end()间的距离)

pointer,表示指针(没看到使用)

reference,表示引用(没看到使用)

其实算法-容器-迭代器他们之间的交互就是用这五种变量,容器创建迭代器时,迭代器获取这五个变量,容器调用算法时,算法获取迭代器的这五个变量.

下面以distance()为例,distance()的方法是算出距离,我们看其源码

namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION // There are two signatures for distance. In addition to the one
// taking two iterators and returning a result, there is another
// taking two iterators and a reference-to-result variable, and
// returning nothing. The latter seems to be an SGI extension.
// -- pedwards
template<typename _InputIterator, typename _Distance>
inline void
__distance(_InputIterator __first, _InputIterator __last,
_Distance& __n, std::input_iterator_tag)//共有三个变量,分别是__first(起始位置),__lase(终点位置),迭代器分类
{                            //此时的迭代器分列是input_iterator_tag,也就意味着这是一种泛华类型,input_iterator_tag他的子类都可以调用这个方法
// concept requirements            //该方法主要负责内存不连续的容器,如bidirectional_iterator_tag
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
while (__first != __last)
{
++__first;
++__n;
}
} template<typename _RandomAccessIterator, typename _Distance>
inline void
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Distance& __n, std::random_access_iterator_tag)//该方法主要负责内存连续的容器使用
{
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__n += __last - __first;
} /**
* This is an SGI extension.
* @ingroup SGIextensions
* @doctodo
*/
template<typename _InputIterator, typename _Distance>
inline void
distance(_InputIterator __first, _InputIterator __last,
_Distance& __n)
{
// concept requirements -- taken care of in __distance
__distance(__first, __last, __n, std::__iterator_category(__first));//根据函数重载调用各自函数
} _GLIBCXX_END_NAMESPACE_VERSION
} // namespace

现在我们来分析一下内存连续的迭代器(random_access_iterator_tag),与内存不连续的迭代器()分别调用__distance(bidirectional_iterator_tag)这个方法时的效率

假设__first与__last的距离为1000000

那么当bidirectional_iterator_tag调用distance()时

      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
while (__first != __last)
{
++__first;
++__n;
}

也就意味着这个函数需要++一百万次

而内存连续的random_access_iterator_tag调用distance时呢

  template<typename _RandomAccessIterator, typename _Distance>
inline void
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Distance& __n, std::random_access_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__n += __last - __first;
}

只需要走一次,此时你应该体验到迭代器对效率的影响了吧

还有advance()函数,我把其源码粘在下面

template<typename _InputIterator, typename _Distance>
inline void
__advance(_InputIterator& __i, _Distance __n, input_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
_GLIBCXX_DEBUG_ASSERT(__n >= );
while (__n--)
++__i;
} template<typename _BidirectionalIterator, typename _Distance>
inline void
__advance(_BidirectionalIterator& __i, _Distance __n,
bidirectional_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_BidirectionalIteratorConcept<
_BidirectionalIterator>)
if (__n > )
while (__n--)
++__i;
else
while (__n++)
--__i;
} template<typename _RandomAccessIterator, typename _Distance>
inline void
__advance(_RandomAccessIterator& __i, _Distance __n,
random_access_iterator_tag)
{
// concept requirements
__glibcxx_function_requires(_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__i += __n;
} /**
* @brief A generalization of pointer arithmetic.
* @param __i An input iterator.
* @param __n The @a delta by which to change @p __i.
* @return Nothing.
*
* This increments @p i by @p n. For bidirectional and random access
* iterators, @p __n may be negative, in which case @p __i is decremented.
*
* For random access iterators, this uses their @c + and @c - operations
* and are constant time. For other %iterator classes they are linear time.
*/
template<typename _InputIterator, typename _Distance>
inline void
advance(_InputIterator& __i, _Distance __n)
{
// concept requirements -- taken care of in __advance
typename iterator_traits<_InputIterator>::difference_type __d = __n;
std::__advance(__i, __d, std::__iterator_category(__i));
} #if __cplusplus >= 201103L template<typename _ForwardIterator>
inline _ForwardIterator
next(_ForwardIterator __x, typename
iterator_traits<_ForwardIterator>::difference_type __n = )
{
std::advance(__x, __n);
return __x;
} template<typename _BidirectionalIterator>
inline _BidirectionalIterator
prev(_BidirectionalIterator __x, typename
iterator_traits<_BidirectionalIterator>::difference_type __n = )
{
std::advance(__x, -__n);
return __x;
} #endif // C++11 _GLIBCXX_END_NAMESPACE_VERSION
} // namespace

下面介绍一下迭代器的基本使用

双向迭代器以list为例

int main () {

    list<int> c = {,,,,};
list<int>::iterator iter = c.begin();
list<int>::iterator iter1 = c.begin(); //存取实际元素
cout<< *iter <<endl; //向前步进(返回新位置)
cout << *(++iter) << endl; //向前步进(返回旧位置)
cout << *(iter++) << endl; //向后步进(返回新位置)
cout << *(--iter) << endl; //向后步进(返回旧位置)
cout << *(iter--) << endl; //迭代器赋值
iter = ++iter;
cout<< *iter <<endl; //判断两个迭代器是否相等 !=判断是否不相等
cout<< (iter1 == iter) << endl; return ;
}

随机迭代器以vector为例

int main () {

    vector<int> c = {,,,,};
vector<int>::iterator iter = c.begin();
vector<int>::iterator iter1 = c.begin(); //取下表为n的元素
cout<<iter[]<<endl; //向前跳n个元素(若n为负,则向后跳)
cout<<*(iter+=)<<endl; //传回iter1和iter2之间的距离
cout<< iter1-iter<<endl; //判断iter1是否在iter之前
cout<<(iter1<iter)<<endl; //判断iter1是否不在iter之后
cout<<(iter1<=iter)<<endl; return ;
}

迭代器的辅助函数

int main () {

    list<int> c = {,,,,};
list<int>::iterator iter = c.begin();
list<int>::iterator iter1 = c.begin(); //使迭代器前进给定的距离
advance(iter, );
cout << *iter <<endl; //返回两个迭代器之间的距离
cout << distance(iter, iter1) <<endl; //使迭代器前进一步
iter = next(iter); cout << *iter << endl; //使迭代器后退一步
iter = prev(iter);
cout << *iter << endl; return ;
}

STL标准库-迭代器的更多相关文章

  1. STL标准库-迭代器适配器

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 这次主要介绍一下迭代器适配器.以reverse_iterator(反向迭代器),insert_iterator(插入迭代器),o ...

  2. STL标准库-算法-常用算法

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 介绍11种STL标准库的算法,从这11种算法中总结一下算法的基本使用 1.accumulate() 累加 2.for_each( ...

  3. STL标准库-容器-set与multiset

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. set与multiset关联容器 结构如下 set是一种关联容器,key即value,value即key.它是自动排序,排序特点依据key se ...

  4. STL标准库-容器-deque

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性. deque双向开口可进可出的容器 我们知道连续内存的容器不能随意扩充,因为这样容易扩充别人那去 deque却可以,它创造了内存 ...

  5. STL标准库-容器-vector

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性. 向量容器vector是一个动态数组,内存连续,它是动态分配内存,且每次扩张的原来的二倍. 他的结构如下 一 定义 vector ...

  6. C++STL标准库学习笔记(五)set

    前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,这一篇后面主要都是我的记录了,为了防止大片蓝色字体出现,后面就不改蓝色 ...

  7. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  8. c/c++ 标准库 迭代器(iterator)

    c/c++ 标准库 迭代器 begin和end运算符返回的具体类型由对象是否是常量决定,如果对象是常量,begin和end返回const_iterator:如果对象不是常量,返回iteraotor 1 ...

  9. STL标准库-容器-set与map

    STL标准库-容器-set与multiset C++的set https://www.cnblogs.com/LearningTheLoad/p/7456024.html STL标准库-容器-map和 ...

随机推荐

  1. POJ 3162 Walking Race(树形dp+单调队列 or 线段树)

    http://poj.org/problem?id=3162 题意:一棵n个节点的树.有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...

  2. FAILED Selenium2Library

    FAILED Selenium2Library Importing test library 'Selenium2Library' failed: ImportError: cannot import ...

  3. 机器学习-数据可视化神器matplotlib学习之路(三)

    之前学习了一些通用的画图方法和技巧,这次就学一下其它各种不同类型的图.好了先从散点图开始,上代码: from matplotlib import pyplot as plt import numpy ...

  4. hdu 3183 A Magic Lamp rmq或者暴力

    A Magic Lamp Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Pro ...

  5. shell until 循环

    until 循环 格式: until condition do command done #输出0-9   #!/bin/bash a=0 until [ ! $a -lt 10 ] do echo ...

  6. pyHook监听用户鼠标、键盘事件

    一.代码部分:获取用户输入信息,并与截图一起保存到XX目录下   # -*- coding: utf-8 -*- #   import pythoncom import pyHook    impor ...

  7. 《A_Pancers团队》———团队项目原型设计与开发

    一.实验目的与要求 (1)掌握软件原型开发技术: (2)学习使用软件原型开发工具:本实验中使用墨刀 二.实验内容与步骤 任务1:针对实验六团队项目选题,采用适当的原型开发工具设计团队项目原型: 任务2 ...

  8. http和WebSocket

    有关http和WebSocket 的区别网上有很多的质料. 个人在此仅仅是记录以下自己的学习心得,自己的理解. 1. http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要 ...

  9. "is not allowed to connect" mysql

    好像过几次,安装mysql时,总会遇到这个问题. 每次都忘怎么解决. 这回写下来吧. 编辑 mysql数据库的 user表太麻烦了, 最简单的方法是加一个用户,以后就用这个用户登录 CREATE US ...

  10. codeforces 576c// Points on Plane// Codeforces Round #319(Div. 1)

    题意:有n个点,找到一个顺序走遍这n个点,并且曼哈顿距离不超过25e8. 由于给的点坐标都在0-1e6之间.将x轴分成1000*1000,即1000长度为1块.将落在同一块的按y排序,编号为奇的块和偶 ...