C++迭代器介绍

162 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

C++迭代器介绍.png

迭代器

string访问字符,vector访问元素可以用下标,但是还有其他的容器却不一定支持,但是都会支持使用迭代器访问元素

迭代器提供了对象的间接访问,也从一个元素移动到下一个元素

使用begin()end()获取迭代器;迭代器的类型由容器类型决定,一般都是T::iterator类型,方便起见,直接使用auto类型更为简单

 auto b = v.begin();  //获取指向容器第一个元素的迭代器
 auto e = v.end(); //获取指向容器尾元素的下一位的迭代器

注意end(),叫尾后迭代器返回的是尾元素的下一位置的迭代器,该迭代器指示的容器一个本不存在的尾后元素,表示已经处理完毕所有的元素;

迭代器类型

  • 迭代器的准确类型一般可以不用知道,使用iterator或者const_iterator表示迭代器的类型

    • 可以使用iterator迭代器访问并修改元素

       vector<int>::iterator it;   //能读写vecotr<int>的元素
       string::iterator it2; //能读写string的元素
      
    • const_iterator和常量指针类似,只能读取不能修改元素

       vector<int>::const_iterator it;  //只能读取vecotr<int>的元素
       string::const_iterator it2;  //只能读取string的元素
      
  • begin()end()返回是否是const迭代器由对象是否是常量决定

    如果对象是const的,那么迭代器就是const_iterator;否者就是iterator

    如果要明确的使用const_iterator,那么可以使用cbegin()cend()

访问元素的方法

和指针类似,可以使用*解引用 也可以使用->直接访问元素的方法

 (it).empty(); //注意括号不能少,因为的优先级比.调用要低
 it->empty();  //这个形式意思就是直接访问it指向的元素的empty方法

迭代器运算符

迭代器运算符.png

比较两个迭代器

如果两个迭代器指向的元素相同 或者都是同一个容器的尾后迭代器,则相等

访问元素

 string s(""hello world");
 //确保迭代器合法
 if (s.begin() != s.end()) {
    //获取迭代器
     auto it = s.begin();
    //访问元素
     it = toupper(it);
 }

通过解引用迭代器来获取它指向的元素

执行解引用的迭代器必须合法并确实指示着某个元素

试图解引用一个非法迭代器或者尾后迭代器是未定义的行为

迭代器移动

  • 使用++或者--,这样迭代器就可以访问上一个或者下一个

     //使用迭代器遍历vector
     //从首元素迭代器一直自增到尾后迭代器,使用++访问下一个元素
     for(auto it = v.begin(); it!=v.end(); ++it) {
       cout << *it <<endl;
     }
    
  • 并不是所有容器都有下标访问方法,所以养成习惯使用迭代器访问元素,就不需要太在意使用的是哪一种容器了,在泛型编程中特别实用

  • 注意,和for类似,在使用迭代器访问容器元素的时候,也不能修改容器的大小(即增删元素)

迭代器运算

  • 迭代器除了自增,自减之外,还能做数值的加减法

     iter + n ; //表示迭代器位置向后移动n位
     iter - n ; //表示迭代器位置向前移动n位
    
  • 迭代器之间还能做减法,返回的是两个迭代器之间的距离

     auto n = iter1 - iter2;
    

    这个返回的类型是difference_type,是带符号的整数

  • 使用关系运算符也可以做比较

    返回的就是两个迭代器指向元素的前后顺序

例子

使用迭代器完成二分查找

 vector<string>::iterator binarySearch(vector<string> v, const string &target)
 {
   auto begin = v.begin();
   auto end = v.end();
   //中间点
   auto mid = begin + (end - begin) / 2;
 ​
   //还有元素,且还没有找到目标
   while (mid != end && *mid != target)
   {
     //目标在前半部分
     if (target < *mid)
     {
       //右边区间收缩
       end = mid;
     }
     //目标在后半部分
     else
     {
       //左边区间后移
       begin = mid + 1;
     }
     //新的中间点
     mid = begin + (end - begin) / 2;
   }
 }