迭代器:是一种可以遍历容器元素的数据类型,它是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。
迭代器(Iterator)是指针(pointer)的泛化,它允许程序员用相同的方式处理不同的数据结构(容器)。
在STL中,容器的迭代器被作为容器元素对象或者I/O流中的对象的位置指示器,因此可以把它理解为面向对象的指针——一种泛型指针或通用指针,不依赖于元素的真实类型。指针代表真正的内存地址,即对象在内存中的存储位置;而迭代器则代表元素在容器中的相对位置。
(1)迭代器类似于C语言里面的指针类型,它提供了对对象的间接访问。
(2)指针是C语言中的知识点,迭代器是C++中的知识点。指针较灵活,迭代器功能较丰富。
(3)迭代器提供一个对容器对象或者string对象的访问方法,并定义了容器范围。
vector,是数组实现的,只要知道数组的首地址,就能访问到后面的元素。所以,我们可以通过访问vector的迭代器来遍历vector容器元素。
List,是链表实现的,我们知道,链表的元素都存储在一段不是连续的地址空间中。我们需要通过next指针来访问下一个元素。那么,我们也可以通过访问list的迭代器来实现遍历list容器元素。
迭代器和容器是密不可分的、紧密相连的的关系。不同的容器,它们的迭代器也是不同的,但是它们的迭代器功能是一样的。假如没有迭代器,由于vector和list容器的存储特点,你需要两种算法去实现遍历vector和list容器的功能,复杂且低效。有了迭代器,遍历容器的效率会大大提高。
下面是各种容器的迭代器的定义方法:
vector迭代器的定义
std::vector<int> ::iterator it; //it能读写vector<int>的元素
std::vector<int>::const_iterator it;//it只能读vector<int>的元素,不可以修改vector<int>中的元素
map迭代器
map<char,string>::iterator it; //it能读写map<char,string>的元素
map<char,string>::const_iterator it;//it只能读map<char,string>的元素,不可以修改map<char,string>中的元素
List迭代器定义
list<int>::iterator it; //it能读写list<int>的元素
list<int>::const_iterator it;//it只能读list<int>的元素,不可以修改list<int>中的元素
用迭代器遍历容器:for( it = vector.begin(); it != vector.end(); it++ )
cout<<*it<<endl;
1) 正向迭代器,定义方法如下:
容器类名::iterator 迭代器名;
2) 常量正向迭代器,定义方法如下:容器类名::const_iterator 迭代器名;
3) 反向迭代器,定义方法如下:容器类名::reverse_iterator 迭代器名;
4) 常量反向迭代器,定义方法如下:容器类名::const_reverse_iterator 迭代器名;
迭代器失效及其危险性
迭代器失效是指当前容器底层存储发生变动时,原来指向容器中某个或某些元素的迭代器由于元素的存储位置发生了改变而不再指向它们,从而成为无效的迭代器。使用无效的迭代器就像使用无效的野指针一样危险。
#include<iostream>
#include<vector>
using namespace std;
void main()
{
vector<int> v; // 未预留空间
v.push_back(2); //引起内存重分配
vector<int>::const_iterator p=v.begin();
for(int i=0;i<10;i++)
{
v.push_back(5); //会引起若干次内存重分配操作
}
cout<<"The first element:"<<*p<<endl; //p已经失效,危险!
}
解决迭代器失效问题:(1)在调用上述操作后重新获取迭代器;(2)在修改容器钱为其预留足够的空闲空间可以避免存储空间重分配。
修改后的正确代码:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
vector<int>::const_iterator it = v.begin();//const_iterator 是常量反向迭代器
int a[10] = {4,2,20,45,2,40,53,34,65,23};
for (int i = 0; i < 10; i++)
{
v.push_back(a[i]); //会引起若干次内存重分配操作
}
it = v.begin(); //重新获取迭代器
cout << "The first element:" << *it << endl; //OK
cout << "遍历迭代器:" << endl;
for (it = v.begin(); it != v.end(); it++)
{
cout << *it << " " ;
}
return 0;
}
迭代器和测试代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
//test1
//string s("abc bdc");
//auto it = s.begin();//编译器会自动识别auto的类型
//while(it != s.end()){
// *it = toupper(*it);//toupper将小写字母转化为大写
// ++it;
//}
//cout << s << endl;
//test2
//string s("abd ddd");
//for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it){
// *it = toupper(*it);
//}
//cout << s << endl;
//test3 不可改变vector::const_iterator类型
/*
vector<int>:: iterator it;
vector<int>:: const_iterator it2;
vector<int> v(5,1);
it = v.begin();
it2 = v.begin();
vector<int> const cv(5,2);
//it = cv.begin();//it是可改变的vector::iterator,所以编译错误
for(auto s : v){
cout << s;
}
cout << endl;
*/
//test4 不可改变string::const_iterator类型
/*
string::iterator sit;
string::const_iterator sit2;
string s1("abc");
sit2 = s1.begin();
while(sit2 != s1.end()){
//*sit2 = toupper(*sit2);
cout << *sit2;
++sit2;
}
cout << endl;
*/
//test5 cbegin和cend,返回const类型的iterator
/*
string s1("aaaa");
auto it1 = s1.cbegin();
//*it1 = 'c';//不可以通过const类型的iterator改变原来的对象
cout << s1 << endl;
vector<int> v(4,2);
auto vit1 = v.cbegin();
//*vit1 = 5;//不可以通过const类型的iterator改变原来的对象
*/
//test6 string迭代器运算
//string s("abcd");
//string s1("abc");
//vector<int> v(5,3);
//auto it1 = s.begin();
//auto it2 = s.begin();
//if(it1 == it2){
// cout << "=" << endl;
//}
//++it1;
//it1 += 1;
//if(it1 > it2){
// cout << ">" << endl;
// cout << it1 - it2 << endl;
//}
//string::difference_type juli = it1 - it2;
//cout << juli << endl;
//test7 vector迭代器运算
/*
vector<string> s(4,"abcd");
vector<string> s1(5,"abc");
auto it1 = s.begin();
auto it2 = s.begin();
if(it1 == it2){
cout << "=" << endl;
}
++it1;
it1 += 1;
if(it1 > it2){
cout << ">" << endl;
cout << it1 - it2 << endl;
}
vector<string>::difference_type juli = it1 - it2;
cout << juli << endl;
*/
/* test8 利用迭代器实现二分法 */
vector<string> v{ "a","b","c","d","e" };
string target("b");
vector<string>::size_type idx = 0;
auto beg = v.begin();
auto mid = v.begin() + v.size() / 2;
auto end = v.end();
while (mid != end && *mid != target) {
if (target < *mid)
end = mid;
else
beg = mid + 1;
mid = beg + (end - beg) / 2;
}
if (mid == end) {
cout << "not found" << endl;
}
else {
idx = mid - v.begin();
cout << idx << ":" << *mid << endl;
}
}