STL(一)——迭代器

迭代器(iterator)

stl的思想是将算法和数据结构分开,而迭代器正是扮演了将他们分开的角色。不管数据结构如何,只要实现了相应的迭代器,就能够使用算法而无需顾及数据内部实现。

 

迭代器类型

试想一下,让你为自己的数据结构设计访问接口,你会怎么设计?比如针对链表,只能单步访问;而针对数组,则可以进行跨步。不同的数据结构有不同的访问限制,由此就引入了不同类型的“接口”。迭代器考虑到了不同数据结构可能存在的不同访问模式,做出了如下分类:

1. 输入迭代器(即单纯的访问)

2. 输出迭代器(即能修改数据的迭代器)

3. 正向迭代器(只能往前走一步的迭代器,如单指针链表)

4. 双向迭代器(可以前后走一步的迭代器,如双向链表)

5. 随机访问迭代器(能任意访问的迭代器,如数组)

 

Trait技法

不同类型的迭代器代表不同的访问效率,算法可能需要根据不同的迭代器类型来选择不同的处理方式,求得最大效率。比如如果数据结构支持随机访问迭代器,那你在对数据进行快排的时候想必不会单步访问排序(正向迭代器)。

我们当然可以在算法里用if来判断迭代器是什么类型来采取不同策略,但进行判断会影响运行时的效率,那有没有办法可以在运行之前知道迭代器类型?答案是trait技法。trait技法利用c++模板特性在编译时就可以根据类型推导知道迭代器类型,保证了运行效率。

下面以advance函数为例子:

根据不同的迭代器设计不同的_advance函数:

//针对输入迭代器(inputiterator)设计的_advance
template <class InputIterator, class Distance>
inline void _advance(InputIterator& i,   
                     Distance       n,   //走多少步
                     input_iterator_tag) //标志迭代器是否为输入迭代器,是一个空结构体
{
    while(n--) ++i;
}

//针对前向迭代器(forwarditerator)设计的_advance
template <class ForwardIterator, class Distance>
inline void _advance(ForwardIterator& i,   
                     Distance       n,   //走多少步
                     forward_iterator_tag) //标志迭代器是否为前向迭代器,是一个空结构体
{
    while(n--) ++i; //和输入迭代器一样
}

//针对双向迭代器(Bidirectionaliterator)设计的_advance
template <class BidirectionalIterator, class Distance>
inline void _advance(BidirectionalIterator& i,   
                     Distance       n,   //走多少步
                     bidirectional_iterator_tag) //标志迭代器是否为双向迭代器,是一个空结构体
{
//双向迭代器,可以前后移动
    if(n>=0)
        while(n--) ++i;
    else
        while(n++) --i;
}

//针对随机访问迭代器(RandomAccessiterator)设计的_advance
template <class RamdomAccessIterator, class Distance>
inline void _advance(RamdomAccessIterator& i,   
                     Distance       n,   //走多少步
                     RandomAccessiterator_iterator_tag) //标志迭代器是否为随机访问迭代器,是一个空结构体
{
    i+=n;
}

以上是不同迭代器类型对应的函数,那么,如果让编译器决定调用哪个函数呢?trait技法。trait实际上是利用c++模板的偏特化特性实现的,代码如下:

//trait
template<class I>
struct iterator_traits{

    typedef typename I::iterator_type iterator_type;  

}

    //实际上,以输入迭代器为例,迭代器代码内部会有这么一句
    //typename input_iterator_tag iterator_type
    //通过将标志输入迭代器的空结构体重命名,编译器可以根据不同类型实例化结构体对象
    //模板根据传入的tag对象类型,使用对应迭代器类型的算法 
    //相当于所有I内部定义的iterator_type都被重名为iterator_type

有了上面都traits,我们就可以将前面都_advance打包成统一都advance函数,给用户调用而无需手动输入迭代器类型。

template<class InputIterator, class Distance>
inline void advance(InputIterator& i, 
                    Distance n)
{
    _advance(i,n,
               iterator_traits<InputIterator>::iterator_type())
}

iterator_traits函数作用比较像“重命名”,因为针对不同迭代器的特化算法实际上是由tag空结构体来标记的,编译器会根据传入tag的类型来决定使用哪个特化版本的算法。而每个迭代器内部都将对应自己的tag位重新命名成iterator_type,iterator_traits类就得以将其对应类型以统一的名字给出。本质上还是将不同的tag位结构体实例化,让编译器根据tag类型不同选择不同的模板。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值