1.迭代器的基本概念

Q1:什么是迭代器?

答:迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。😧
(看不懂,没关系,c语言学过吧,指针知道吧,没错,这就和访问数组的指针类似,指针是C语言里面就有的东西,而迭代器是C++里面才有的,二者还有其他区别,之后再整理😁)
在这里插入图片描述

Q2:为什么要使用迭代器?

  • STL提供每种容器的实现原理各不相同,如果没有迭代器我们需要记住每一种容器中对象的访问方法,很显然这样会变得非常麻烦

  • 每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说操作方法是一致的,也就说通过迭代器统一了对所有容器的访问方式

  • 迭代器的使用可以提高编程的效率

2.迭代器的使用

1.基本使用方法

  • 首先要定义一个迭代器类型变量(这里以vector容器为例)
    定义方法如下:容器类名::iterator 迭代器名;
    如要定义vector容器的迭代器:vector<int>::iterator iter;(这里的iter是变量名,可以自定义)
  • 接下来要利用迭代器访问容器数据
    先要了解几个成员函数
成员函数功能
begin()返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向选代器。
end()返回指向容器最后一个元素之后一个位置的正向迭代器,如果是 onst 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin0搭配使用。
rbegin()返回指向最后一个元素的反向迭代器,如果是 const 类型容器,在该函数返回的是常量反向迭代器。
rend()返回指向第一个元素之前一个位置的反向迭代器。如果是 onst 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 begin0 搭配使甲。

这里的end()函数要注意,不是指向容器最后一个元素而是后一个位置看图
在这里插入图片描述
现在来看代码:

int arr[] = {10, 20, 30, 40, 50};
    vector<int> v1;
    v1.assign(arr, arr + 5);//以上为创建一个含有5个元素的vector容器
    vector<int>::iterator iter;//定义迭代器类型变量
    iter = v1.begin();//变量被赋值为指向第一个元素的迭代器
    cout << *iter << endl;
    iter++;//可以用自增操作,让iter指向下一个元素
    cout << *iter << endl;
    iter = v1.begin() + 2;//让iter指向容器中第三个位置
    cout << *iter << endl;
    **结果:10
           20
           30

注意:vector容器迭代器属于随机访问迭代器,可以一次移动多个位置,如iter=v1.begin()+2;
也可以用iter=iter+2;
下面是容器数据的遍历

int arr[] = {10, 20, 30, 40, 50};
    vector<int> v1;
    v1.assign(arr, arr + 5);
    vector<int>::iterator iter;
    for (iter = v1.begin(); iter != v1.end(); iter++)//注意终止条件
        cout << *iter << ' ';
    cout << endl;
    **结果:10 20 30 40 50

注意:上面说到end()函数是指向容器元素的最后一个元素的后一个位置,所以当迭代器指向最后的后一个位置时结束遍历,便可以访问所有容器元素😎

3.迭代器失效

什么是迭代器失效,先看一个案例:

vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4); //到这里总共插入4个元素
    vector<int>::iterator it;
    it = v1.begin() + 3; //这里的it指向元素4
    cout << *it << endl;
    v1.insert(it, 8); //在it指向的位置插入8
    cout << *it << endl;
    
    **结果:4
           555  //错误数字

思考:根据之前所学习的内容,在元素4的位置插入元素8,4会自动后移,迭代器it理应会指向元素8的位置,但是事实却不是这样💘❓

原因:在插入一个元素后,容器会在空间内再开辟一块新的空间来存放容器数据,(类似于深拷贝),但是迭代器it所指向的依旧是原来的空间,所以会出现乱码👍

那么怎样解决这个问题呢😟
看优化后的代码:

vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);
    vector<int>::iterator it;
    it = v1.begin() + 3; //insert会返回一个新的有效的迭代器
    cout << *it << endl;
    it=v1.insert(it, 8); 
    cout << *it << endl;
    **结果:4
           8

看到代码的变化了吗,只要对迭代器变量进行重新赋值就好了,这样迭代器便会指向新的空间

下面再看一下erase()函数导致的迭代器失效

vector<int> v1;
    v1 = {1, 2, 3, 3, 3, 3, 4, 5};
    vector<int>::iterator it;
    for (it = v1.begin(); it != v1.end(); it++) {
        if (*it == 3)
            v1.erase(it); //判断如果是3,就执行删除操作
    }
    for (it = v1.begin(); it != v1.end(); it++)
        cout << *it << ' ';
    cout << endl;
    **结果:1 2 3 3 4 5 //不符合预期

为什么没有将元素3全部删除👀

解释:因为删除的机制就是在删除一个元素后,后面的元素会向前移动,但是迭代器的指向位置不变,所以会跳过一些满足条件的数,导致无法完全删除。

解决

vector<int> v1;
    v1 = {1, 2, 3, 3, 3, 3, 4, 5};
    vector<int>::iterator it;
    for (it = v1.begin(); it != v1.end(); ) {
        if (*it == 3)
            it=v1.erase(it);  //每次对it重新赋值,使其指向最新的有效的迭代器
        else
            it++;
    }
    for (it = v1.begin(); it != v1.end(); it++)
        cout << *it << ' ';
    cout << endl;
    **结果:1 2 3 4

解释:这里通过控制,迭代器后移的条件,来解决会跳过某些元素的可能😊

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐