答:迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。
(看不懂,没关系,c语言学过吧,指针知道吧,没错,这就和访问数组的指针类似,指针是C语言里面就有的东西,而迭代器是C++里面才有的,二者还有其他区别,之后再整理)
STL提供每种容器的实现原理各不相同,如果没有迭代器我们需要记住每一种容器中对象的访问方法,很显然这样会变得非常麻烦
每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说操作方法是一致的,也就说通过迭代器统一了对所有容器的访问方式
迭代器的使用可以提高编程的效率
容器类名::iterator 迭代器名;
vector::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()函数是指向容器元素的最后一个元素的后一个位置,所以当迭代器指向最后的后一个位置时结束遍历,便可以访问所有容器元素
什么是迭代器失效,先看一个案例:
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
解释:这里通过控制,迭代器后移的条件,来解决会跳过某些元素的可能