• 迭代器


    我们知道可以使用下标运算符来访问,string对象的字符或者vector对象的元素。还有另外一种机制可以实现同样的目的。这就是迭代器。除了vector之外,标准库还定义了其他几种容器。所有标准库容器都可以使用迭代器,但是其中只有少数几种才同时支持下标运算符,类似指针类型,迭代器也提供了对对象的间接访问。就是迭代器而言,其对象是容器中的元素或者string对象中的字符。使用迭代器可以访问某个元素,迭代器也能从一个元素移动到另外一个元素。迭代器有有效和无效之分,这一点和指针类似。

    1、使用迭代器:

    和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员。比如这些类型都拥有begin和end的成员,其中begin成员负责返回指向第一个元素(或第一个字符)的迭代器。

    1
    auto b=v.begin(),e=v.end();//b和e的类型相同

    end成员则负责返回指向容器(或string对象),“为元素的下一位置”的迭代器。也就是该迭代器知识的是容器一个根本不存在的”尾后“元素。这样迭代器没有什么含义,只是一个标记而已,表明我们已经处理完了容器中的所有元素。end成员返回的迭代器常被称作尾后迭代器或者简称为尾迭代器。特殊情况下如果容器为空,则begin和end返回的是同一个迭代器。

    如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。

    2、迭代器运算符:

    * iter 返回迭代器iter所指元素的引用
    iter->mem 解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem
    ++iter 令iter指示容器中的下一个元素
    --iter 令iter指示容器中的上一个元素
    iter1==iter2 判断两个迭代器是否相等(不相等)。
    iter1!=iter2 如果两个迭代器指示1的是同一个元素或者他们是同一个容器的尾后迭代器,则相等,反之则不等。

    和指针类似,也能通过解引用迭代器来获取他所指示的元素,执行解引用的迭代器必须合法并确实指示着某个元素。试图解引用一个非法迭代器或尾后迭代器都是为被定义的行为。

    3、将迭代器从一个元素地用到另外一个源素:

    迭代器使用++运算符。来从一个元素移动到下一个元素。从逻辑上来说,迭代器的递增和整数的递增类似。整数的递增是在整数值上加一,迭代器的递增是将迭代器向前移动一个位置。

    因为end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或解引用的操作。

    1
    2
    3
    4
    5
    6
    7
    string s("wangs huai");
        for (auto t = s.begin(); t != s.end() && !isspace(*t); t += 1)
        {
            *t = toupper(*t);
        }
        cout << s << endl;
        getchar();

    循环首先用s.begin的返回值来初始化t,意味着t指示的是s中的第一个字符。条件部分检查是否已到达的、s的尾部。如果没有到达,则将t解引用的结果传入isspace函数检查是否遇到了空白。每次迭代的最后,执行++t令迭代器向前移一个位置访问s的下一个字符。

    循环内部和上一个程序if语句的最后一句话一样,先解引用t,然后将结果传入toupper函数得到该字母对应的大写形式,再把这个大写字母重新赋值给t所指示的字符。

    注意:解引用和成员访问操作:(*t).empty。为了简化这个操作,可以使用->(箭头运算符),将解引用和成员访问两个操作结合起来,也就是说t->mem和(*t).mem(),表达的意思是相同的。

    4、迭代器类型。

    就像不知道string和vector独享的类型一样,我们同样不知道(不用知道)迭代器的精确类型。而实际上,那些拥有迭代器类型的标准库库类型使用iterator和const_iterator来表示迭代器的类型。

    注意:迭代器类型和迭代器:

    迭代器有3种不同的概念:(1)迭代器(2)指容器定义的迭代器类型(3)某个迭代器对象

    5、begin和end运算符:
    他们的返回具体类型由对象是否是常量决定,如果是常量,begin和end返回的是const_iterator,如果对象不是常量,返回iterator;

    6、某些对vector对象的操作会对迭代器失效:

    vector对象可以动态的延长,但是也会有一些副作用,已知一个限制是不能在范围for循环中向vector对象添加源素。另外一个限制是任何一种可能改变vector对象容量的操作,比如:push_back,都会使该vector对象的迭代器失效。

    凡是我们使用了迭代器的循环体,都不要向迭代器所属的容器中添加源素。

    7、迭代器运算:

    迭代器递增运算每次移动一个元素,所有标注库容器都有支持递增运算的迭代器。类似的,也能用==和!=对任意标准库类型的两个有效迭代器进行比较。

    string和vector的迭代器提供了更多的运算符。一方面可以迭代器每次移动跨过多个元素,另外也支持迭代器进行关系运算。所有这些运算被称为迭代器运算。

    vector和string迭代器支持的运算:

    iter+n 迭代器加上一个整数值任得一个迭代其,迭代器指示的新位置与原来相比向前移动了n个位置。
    iter-n 迭代器减去一个整数值任得一个迭代其,迭代器指示的新位置与原来相比向后移动了n个位置。
    iter1+=n 迭代器加法的复合赋值语句,将iter加n的结果赋给iter1
    iter-=n 迭代器减法的复合赋值语句,将iter1-n的结果赋值给iter1
    iter1-iter2 得到他们之间的距离

    8、迭代器的算术运算:

    可以令迭代器和一个整数值相加(或相减),其返回值是向前或者向后移动了若干个位置的迭代器。执行这样的操作时,结果迭代器或者指示原vector对象(或string对象)内的一个元素,或者指示原vector对象(string对象)尾元素的下一个位置。

    例如:计算最接近中间元素的算法:mid=begin+(size)/2;

    对于sring和vector对象的迭代器来说,除了判断是否相等,还能使用关系运算符对其进行比较。

    if(t<mid)//处理前半部分的元素。

    9、使用迭代器运算:

    使用迭代器运算的一个经典算法就是二分查找。用二分查找实现迭代器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include<iostream>
    #include<string>
    #include<vector>
    using std::vector;
    using namespace std;
    int main()
    {
        int sought = 0;
        vector<int>myvector{1,3,2,4,5,0,9,6,8,7};
        auto beg = myvector.begin(), end = myvector.end();
        auto mid = beg + (end - beg) / 2;
        while (mid != end&&*mid != sought)
        {
            if (sought < *mid)
            {
                end=mid;
            }
            else
            {
                beg = mid + 1;
            }
            mid = beg + (end - beg) / 2;
        }
        cout << sought << ":" << endl;
        getchar();
        return 0;
    }

    程序刚开始就定义了三个迭代器:被恶搞指向搜索范围内的第一个元素,end指向尾元素的下一位置,mid指向中间那个元素。初始状态下,搜索范围是名为myvector的vector《string》的全部范围。

    循环部分先判断所搜范围是否为空,如果mid和end当前值相等,说明已经找遍了所有元素。此时条件不满足,循环终止。当搜索范围不为空是,可知密度指向了某个元素,检查该元素是否就是我们所要搜索的,如果是就终止循环。

    当进入循环内部之后,程序通过某种规则移动beg或者end来缩小范围。

    注意:就像不知道string和vector的size_type成员到底是什么类型一样,一般说来,我们也不知道(不用知道)迭代器的精确类型。而实际上,那些拥有迭代器的标准库类型使用iterator和const_iterator来表示迭代器的类型。

    注意:iterator是迭代器的意思,const_iterator是常迭代器,是用来读取数据的。

  • 相关阅读:
    获取IPhone相册中图片的方法(包括获取所有图片)
    CocoaPods的安装与使用介绍
    屏幕截图
    图片水印(微博图片上面的个人签名)
    info.plist选项含义
    最苦恼的又重要的屏幕适配
    Redis
    python的约束库constraint解决《2018刑侦科题目》
    start to learn python!
    用户体验分析: 以 “南通大学教务管理系统微信公众号” 为例
  • 原文地址:https://www.cnblogs.com/yjds/p/8597260.html
Copyright © 2020-2023  润新知