STL迭代器

STL迭代器

迭代器是一种行为类似指针的对象,而指针的各种行为中最重要的便是内容提领和成员访问,因此,迭代器最重要的编程工作就是对operator* 和operator->进行,下面以find函数为例:

    template <class InputIterator,typename T>
    InputIterator find(InputIterator fitst,InputIterator end,T value){
        while(fist!=end&&*first!=value)++first;
        return first;
    }

从上例可以看出算法和迭代器的合作,实现了以相同算法对不同容器的访问。
接下来,我们来为一个单向链表list设计一个迭代器。假设list的结构如下

    template <typename T>
    class ListItem{
        private:
            T _value;
            ListItem *_next;
        public:
            ListItem(T value){
                _value=value;
                _next=NULL;
            }
            T value() cosnt {return _value;}
            ListItem* next() const {return _next;}
    };
    template <typename T>
    class List{
        private:
            long _size //链表长度
            ListItem<T> *first;
            ListItem<T> *end1;
        public:
            List(){
                _size=0;
                first=end=NULL;
            }
            void push(T value){
                ++_size;
                end1=new ListItem<T>(value);
                if(first==NULL){
                    first=end1;
                }
                end1=end1->next();
            }
            ListItem* front() const {return first;}
            ListItem* end() const {return end1;}
            void display() const {
                for(ListItem<T> *p=first;p;p=p->next())
                    cout<<p->value()<<" ";
                cout<<endl;
            }
            long size() const {return _size;}
    };

下面是链表迭代器的简单实现

template <class Item>
class ListIter{
    private:
        Item *ptr;
    public:
        ListIter(Item *p=0): ptr(p){}
        Item& operate*() const {return *ptr;}
        Item* operate->() const {return ptr};
        ListIter& operate++(){
            ptr=ptr->next();
            return *this;
        }
        ListIter operate++(int){
            ListIter temp=*this;
            ++*this;
            return temp;
        }
        bool operator==(const ListIter &arg) const {return arg.ptr==ptr;}
        bool operator!=(const ListIter &arg) const {return arg.ptr!=ptr;}
};

代码测试

int main(){
    List<int> *mylist=new List<int>;
    for(int i=0;i<5;++i)mylist->push(i);
    mylist->display(); //(0 1 2 3 4)
    ListIter<ListItem<int> > begin(mylist->front());
    ListIter<ListItem<int> > end1(mylist->end());
    ListIter<ListItem<int> > iter;
    iter=find(beigin,end,3)//从链表中查找3
    if(iter==end)cout<<"NO FOUND"<<endl;
    else cout<<"FOUND"<<endl;
    return 0; 
}

注意,由于find()函数内以*iter!=value来检查元素值是否吻合,有些是value原型是int,iter的型别是ListItem,两者之间无可供使用的operator!=,所以必须另写一个全局的operator!=重载函数,并以int
和ListItem作为他的两个参数:

template <typename T>
bool operator!=(const ListItem<T> &item,T value){
    return item->value()!=value;
}

从上面的实现可以看出,为了完成一个针对List而设计的迭代器,我们暴露了太多List实现细节,载mian()之中为了制作end 和begin 两个迭代器,我们暴露了ListItem,在ListIter class中为了达成operator++
的目的,暴露了ListItem的next函数。换句话说,要设计出ListIter,首先必须对List的实现细节有非常丰富的了解。为了解决这一问题,STL将迭代器的实现交给了容器,每种容器都会以嵌套的方式在内部定以专属的迭代器,各种迭代器的接口相同,内部实现却不同,这也体现了泛型编程的概念。

迭代器的相应型别

1.value_type:

所谓value_type,是指迭代器所指对象的型别,任何一个打算与STL算法有完美搭配的class,都应该定义自己的value_type内嵌类别。

2.difference_type:

difference_type用来表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量,因为对于连续空间的容器而言,头尾之间的距离就是其最大容量。如果一个泛型算法提供计数功能,列入STL中的count(),其传回值就必须用迭代器的diffrence_type:

template <class I,class T>
typename iterator_traits<T>::difference_type 
    count(I first,I end,const T& value){
        typename iterator_traits<T>::difference_type n=0;
        for(;first!=end;++first){
            if(*first==value)++n;
        }
        return n;
}

针对相应型别difference_type,traits有如下的两个特化版本,

template <class I>
struct iterator_traits{
    typedef typename I::difference_type difference_type;
};
//指针
template <class I>
struct iterator_traits<T*>{
    typedef ptrdiff_t difference_type;
};
//const指针
template <class I>
struct iterator_traits<const T*>{
    typedef ptrdiff_t difference_type;
};
3.reference_type:

在c++中,如果函数要传回左值,都是以by reference 的方式进行,所以当p是个mutable iterators时,如果其value_type是T,那么*p的型别不应该是T,应该是T&。将此道理扩充,如果p是一个constrant iterators,其value_type是T,那么*p的型别不应该是const T,应该是const T&,这里所讨论的*p的型别,既所谓的reference_type,实现在下面

4.pointer_type

pointers和reference 在c++中有非常密切的联系,如果“传回一个左值,令它代表p所指之物”是可能的,那么“传回左值,令它代表p所指之物的地址”也一定可以,也就是说,我们能够传回一个pointer,指向迭代器所指之物。
这些相应型别在先前的ListIter class中出现过

Item& operator*()const{return *ptr;}
Item* operator->()const{return ptr;}

Item&便是ListIter的reference_type,Item*便是其pointer_type。
现在我们把reference_type和pointer type 这两个型别加入traits中

template <class I>
struct iterator_traits{
    typedef T* pointer;
    typedef T& reference;
};
//指针
template <class I>
struct iterator_traits<T*>{
    typedef T* pointer;
    typedef T& reference;
};
//const指针
template <class I>
struct iterator_traits<const T*>{
    typedef T* pointer;
    typedef T& reference;
};
5.iterator_category

最后一个迭代器的相应型别会引发较大规模的写代码工程,在那之前,先要知道迭代器的分类。
这里写图片描述
这里写图片描述
设计算法时,如果可能,我们尽量针对上图的某种迭代器提供一个明确定义,并针对更强化的某种迭代器提供另一种定义,这样才能在不同情况下提供最大效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值