迭代器
什么是迭代器?
- 迭代器是一种检查容器内元素并且遍历容器内元素的数据类型
迭代器的作用:
- 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围
为什么需要迭代器?
- STL提供每种容器的实现原理各不相同,如果没有迭代器我们需要记住每一种容器中对象的访问方法,很显然这样会变得非常麻烦
- 每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说操作方法是一致的,也就说通过迭代器统一了对所有容器的访问方式。例如:无论哪个容器,访问当前元素的下一个元素我们可以通过迭代器自增进行访问
vector容器的iterator类型
vector<int>::iterator iter; //变量名为iter
vector容器的选代器属于"随机访问选代器",迭代器一次可以移动多个位置
成员函数 | 功能 |
begin() | 返回指向容器中第一个元素的正向迭代器;如果是const 类型容器,在该的数返回的是常量正向迭代器 |
end() | 返回指向容器最后一个元素之后一个位置的正向法代器;如果是 const 类型容器,在该函教返回的是常量正向迭代器。此的数通常和 begin()搭配使用 |
rbegin() | 返回指向最后一个元素的反向选代器;如果是const 类型容器,在该函数返回的是常量反向选代器 |
rend() | 返回指向第一个元素之前一个位置的反向迭代器。如果是 const 类型容器,在该的数返回的是常量反向迭代器。此的数通常和 rbegin()搭配使用 |
cbegin() | 和 begin()功能类似,只不过其返回的选代器类型为常量正向选代器,不能用于修改元素 |
cend() | 和 end()功能相同,只不过其返回的选代器类型为常量正向迭代器,不能用于修改元素 |
crbegin() | 和 rbegin()功能相同,只不过其返回的选代器类型为常量反向选代器,不能用于修改元素 |
crend() | 和 rend()功能相同,只不过其返回的选代器类型为常量反向选代器,不能用于修改元素 |
示例:
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> vectA;
int Array[] = { 100,1,20,30,40 };
vector<int>::iterator iter;
vectA.assign(Array, Array + 5);
for(iter=vectA.begin();iter<vectA.end();iter++){
cout << *iter << " ";
}
cout << endl;
}
迭代器失效
由于迭代器本身并不是一个普通的指针,直接输出迭代器的地址可能不会得到你想要的结果。
迭代器失效的本质确实是地址的改变,但这只是一个方面。迭代器失效的原因不仅限于地址的改变,还涉及到容器内部数据结构的变化。具体来说,迭代器失效可以由以下几种情况引起:
-
地址的改变:
- 当删除一个元素时,如果该元素不是容器的最后一个元素,容器会将后面的元素向前移动以填补空位。这会导致这些元素的地址发生变化,从而使指向这些元素的迭代器失效。
-
容器内部数据结构的变化:
- 容器内部可能有多种数据结构,如动态数组、链表等。在某些情况下,删除或插入操作可能会导致容器重新组织其内部数据结构,从而导致迭代器失效。
插入元素
示例:如下面代码所示,在对vector容器使用insert()函数时,会将原来存储数据的空间释放掉,重新开辟新的空间进行赋值,所以当运行到 cout << *it << endl; 这行代码时,会出现报错,因为没有权限去访问原先vector数据所对应的空间
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::iterator it = v.begin() + 3;
v.insert(it, 8);
cout << *it << endl;
}
正确示例:
insert()是可以返回新开辟空间所插入相应位置的地址的
using namespace std;
int main() {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int>::iterator it = v.begin() + 3;
it = v.insert(it, 8);
cout << *it << endl;
cout << &(*(v.begin())) << endl;
}
删除元素
示例:
如下面所示,当我们进行数据的删除时,若是对容器中最后一个数据进行删除则不会有影响,带如果删除的数据不在末尾,则会造成容器内部数据结构的改变,从而导致迭代器失效,因此最保守的方式就是每次在进行删除操作后都更新迭代器(虽然erase不会重新分配地址)
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> cond = { 1,2,3,3,3,3,4,5,6 };
vector<int>::iterator it;
for (it = cond.begin(); it != cond.end();) {
if (*it == 3) {
cout << "before del" << &(*it) << endl;
it = cond.erase(it);
cout << "after del" << &(*it) << endl;
}
else { it++; }
}
for (it = cond.begin(); it != cond.end(); it++) {
cout << *it << ' ';
}
}