简单来说,迭代器就是用来遍历容器的。
举个栗子:对于int型数组除了用下标访问,还可以通过指针访问,实际上迭代器就是对指针进行了封装。
通过代码了解一下,自己实现简单的迭代器:
#include
#include
using namespace std;
void show(int* begin, int* end)//自己写的输出函数
{
while (begin != end)
{
cout << *begin << " ";
begin++;
}
}
int main()
{
int arr[] = { 1,2,3,4,5,68,5,2,14,5,8,4,5,8,2,5,4,5,65,9 };
int len = sizeof(arr) / sizeof(arr[0]);//求出数组元素个数
//指针访问
int* begin = arr;
int* end = arr + len;
show(begin, end);//在容器中,begin,和end就是迭代器,底层封装了指针
while (1);
return 0;
}
当我们把show函数编程模板函数之后,就可以输出任意类型的数组了:
template
通过这个例子我们知道了,可以通过迭代器实现算法和容器的分离(show函数可以适配不同类型的数组)。所以说迭代器是一个很强的东西~大家好好学哈
STL 标准库为每一种标准容器定义了一种迭代器类型,这意味着,不同容器的迭代器也不同,其功能强弱也有所不同。
常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器 5 种
输入迭代器 :也有叫法称之为“只读迭代器”,它从容器中读取元素,只能一次读入一个元素向前移动,只支持一遍算法,同一个输入迭代器不能两遍遍历一个序列。
输出迭代器 :也有叫法称之为“只写迭代器”,它往容器中写入元素,只能一次写入一个元素向前移动,只支持一遍算法,同一个输出迭代器不能两遍遍历一个序列。
正向迭代器 :组合输入迭代器和输出迭代器的功能,还可以多次解析一个迭代器指定的位置,可以对一个值进行多次读/写。
双向迭代器 :组合正向迭代器的功能,还可以通过++操作符向后移动位置。
随机访问迭代器 :组合双向迭代器的功能,还可以向前向后跳过任意个位置,可以直接访问容器中任何位置的元素。
迭代器 | 操作 |
---|---|
所有迭代器 | it++、++it |
输入迭代器 | *it、it1=it2、it1==it2、it1!=it2 |
输出迭代器 | *it、it1=it2 |
正向迭代器 | 提供输入输出迭代器的所有功能 |
双向迭代器 | it--、--it |
随机迭代器 | +=、-=、+、-、[]、<、<=、>、>= |
容器 | 对应迭代器类型 |
---|---|
array | 随机访问迭代器 |
vector | 随机访问迭代器 |
deque | 随机访问迭代器 |
list | 双向迭代器 |
set / multiset | 双向迭代器 |
map / multimap | 双向迭代器 |
forward_list | 前向迭代器 |
unordered_map / unordered_multimap | 前向迭代器 |
unordered_set / unordered_multiset | 前向迭代器 |
stack | 不支持迭代器 |
queue | 不支持迭代器 |
前面我们说过迭代器实质上就是封装的指针,那么怎么封装的呢?
还是看代码吧~
#include
using namespace std;
class MyIterator
{
public:
MyIterator(int* ptr) :_ptr(ptr) {}
int* operator++()//模仿指针前置++操作
{
_ptr++;
return _ptr;
}
int& operator*()//模仿对指针的取值操作
{
return *_ptr;
}
bool operator!=(MyIterator end)//模仿指针的比较
{
return _ptr != end._ptr;
}
private:
int* _ptr;
};
int main()
{
int arr[] = { 1,2,3,4,5,68,5,2,14,5,8,4,5,8,2,5,4,5,65,9 };
int len = sizeof(arr) / sizeof(arr[0]);
//模拟迭代器访问
MyIterator begin = arr;
MyIterator end = arr + len;
for (begin; begin != end; ++begin)
{
cout << *begin << " ";
}
while (1);
return 0;
}
把指针封装到类里面,这样就可以轻松使用了,不用担心出现乱七八糟的问题。
但是,细心的同学会发现,操作的时候是不用指针了,直接操作迭代器就行,但是赋值的时候还是指针呀~这可咋解决呢?
不要着急,请听我娓娓道来~我们可以把赋值的指针再封装一层,直接返回一个迭代器。不过这里的任务就比较庞大了,
首先 ,需要把数组用类封装(自己实现简单的vector);
然后 ,把我们刚刚写好的迭代器类稍加修改,放到类中(迭代器是一个类中类);
最后 ,直接把数组的首地址,和最后一个元素的下一个位置分别封装成返回迭代器的begin()和end()函数
直接上代码:
template<typename Data>
class Vector
{
public:
Vector() :_Array(nullptr), _curSize(0), _capacity(0) {}
Vector(int size) :_curSize(0), _capacity(size)
{
_Array = new Data[size];
}
void push_back(Data elem)//插入元素
{
if (_curSize < _capacity)
{
_Array[_curSize] = elem;
_curSize++;
return;
}
}
Data& operator[](int index)//提供下标法访问元素
{
if (index >= 0 && index < _capacity)
{
return _Array[index];
}
cout << "数组访问越界" << endl;
}
~Vector()
{
delete[] _Array;
}
public://实现迭代器
class iterator
{
public:
iterator() :_ptr(nullptr) {}
iterator(Data* ptr) :_ptr(ptr) {}
iterator(const iterator& it)
{
this->_ptr = it._ptr;
}
~iterator() {}
iterator operator=(iterator it)
{
this->_ptr = it._ptr;
return *this;
}
bool operator!=(iterator it)
{
return _ptr != it._ptr;
}
iterator operator++(int)
{
iterator temp = *this;
_ptr++;
return temp;
}
Data& operator*()
{
return *_ptr;
}
Data* operator->()
{
return _ptr;
}
private:
Data* _ptr;
};
//提供用于迭代的begin和end函数,这两个函数一定要放在迭代器类的后面
iterator begin() //返回数组首地址
{
iterator t(_Array);
return t;
}
iterator end()//返回数组,最后一个元素的一下一个位置的地址
{
iterator t(&_Array[_curSize]);
return t;
}
private:
Data* _Array;//数组指针
int _curSize;//数组当前元素大小
int _capacity;//数组最大容量
};
代码测试:
void Test()
{
Vector<int> vec(10);
for (int i = 0; i < 10; i++)
{
vec.push_back(i);
}
//能通过迭代器访问嘛?不能,要自己实现迭代器之后才能使用
for (Vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
ok,完美~
全部0条评论
快来发表一下你的评论吧 !