1. 迭代器简介
- 定义:迭代器是一种数据类型,用于遍历容器中的元素。与C语言中的指针类似,迭代器允许我们访问容器中的元素,但提供了更丰富的操作和功能。
- 用途:通过迭代器,我们可以读取、修改容器中某个迭代器所指向的元素值。迭代器支持++、--等操作符,可以从容器中的一个元素移动到另一个元素。
- 类型:C++标准库为不同的容器定义了不同类型的迭代器。根据功能的不同,迭代器可以分为输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。
2. 迭代器的使用
- 定义迭代器:使用
容器类型::iterator
关键字定义迭代器变量,如std::vector<int>::iterator it;
。 - 初始化迭代器:使用
begin()
和end()
函数获取容器的起始迭代器和末尾迭代器,如it = vec.begin();
。 - 遍历容器:使用while或for循环遍历容器,通过
*it
访问当前迭代器所指向的元素,使用++it
将迭代器移动到下一个元素。
3. 迭代器的常见操作
- 访问元素:通过解引用操作符
*
访问迭代器所指向的元素,如int value = *it;
。 - 移动迭代器:使用++、--操作符将迭代器向前或向后移动一个位置。
- 比较迭代器:可以使用==、!=、<、<=、>、>=等操作符比较两个迭代器的位置关系。
4.迭代器的分类 iterator_category
- std::input_iterator_tag 输入迭代器,最基本的迭代器类型,只能向前移动一次(每个元素只能被读取一次)不支持向后且不能读取多次 示例:std::istream_iterator(用于从输入流中读取数据)。
- std::output_iterator_tag 输出迭代器 输出迭代器只能递增,以指向下一个输出位置。示例:std::ostream_iterator(用于将数据写入输出流)。
- std::forward_iterator_tag 前向迭代器。这种迭代器可以多次读取同一个元素,也可以安全地递增以移动到下一个元素。前向迭代器提供了一对多(one-to-many)关系,即一个迭代器可以指向多个元素(通过递增操作),但每个元素只被一个迭代器指向。 例如vector<T>::iterator
- std::bidirectional_iterator_tag 双向迭代器。除了前向迭代器的功能外,它还支持递减操作,因此可以向后移动到前一个元素。 例如list<T>::iterator dqeue<T>::iterator
- std::random_access_iterator_tag 随机访问迭代器,它支持上述所有操作,并且还提供了“算术”功能,如加法和减法操作符,以及比较操作符(如 <, <=, >, >=)。这使得可以在常数时间内计算两个迭代器之间的距离,并直接跳转到序列中的任何位置。示例:vector<T>::iterator deque<T>::iterator array<T>::iterator
总而言之,迭代器是一个封装了指针的对象(不仅仅只有指针),并且这个对象不仅能实现指针的功能,还能扩展其他的功能
这里我们以标准库vector迭代器为例子
这里我们能看到vector的迭代器继承了标准库下 随机访问迭代器,从vector动态数组我们知道它可以随机访问元素
struct _Bit_iterator_base
: public std::iterator<std::random_access_iterator_tag, bool>
{
_Bit_type * _M_p;
unsigned int _M_offset;
_Bit_iterator_base(_Bit_type * __x, unsigned int __y)
: _M_p(__x), _M_offset(__y) { }
void
_M_bump_up()
{
if (_M_offset++ == int(_S_word_bit) - 1)
{
_M_offset = 0;
++_M_p;
}
}
void
_M_bump_down()
{
if (_M_offset-- == 0)
{
_M_offset = int(_S_word_bit) - 1;
--_M_p;
}
}
void
_M_incr(ptrdiff_t __i)
{
difference_type __n = __i + _M_offset;
_M_p += __n / int(_S_word_bit);
__n = __n % int(_S_word_bit);
if (__n < 0)
{
__n += int(_S_word_bit);
--_M_p;
}
_M_offset = static_cast<unsigned int>(__n);
}
bool
operator==(const _Bit_iterator_base& __i) const
{ return _M_p == __i._M_p && _M_offset == __i._M_offset; }
bool
operator<(const _Bit_iterator_base& __i) const
{
return _M_p < __i._M_p
|| (_M_p == __i._M_p && _M_offset < __i._M_offset);
}
bool
operator!=(const _Bit_iterator_base& __i) const
{ return !(*this == __i); }
bool
operator>(const _Bit_iterator_base& __i) const
{ return __i < *this; }
bool
operator<=(const _Bit_iterator_base& __i) const
{ return !(__i < *this); }
bool
operator>=(const _Bit_iterator_base& __i) const
{ return !(*this < __i); }
};
5.迭代器对算法的影响
这里以distance为例子也就是求任意两个迭代器的距离(位置差)例如求vector的end-begin也就是整个vector的大小
我们知道stl中算法和容器是相互独立的算法在对数据操作时需要知道的东西有,iterator_category 迭代器的类型,iterator指向的数据类型T,iterator指向的数据类型T,iterator指向数据类型T的pointer,diffrence_type两个迭代器之间的差值类型
在这里我们用到了差值类型和迭代器类型
template<class InputIterator>
inline
iterator<InputIterator>::difference_type distance(InputIterator first,InputIterator last)
{
/*通过迭代器萃取获取迭代器类型*/
typedef typename iterator_traits<InputIterator>::iterator_category category;
return __distance(first,last,category()); //根据迭代器的类型走相应的函数 偏特化
}
这里有两种模板
/*计算非随机迭代器计算位置差*/
template<class InputIterator> //例如list,forward_list
inline
iterator<InputIterator>::difference_type
distance(InputIterator first,InputIterator last,input_iterator_tag)
{
iterator_traits<InputIterator>::difference_type n=0;
while(first!=last)
{
++first;++n;
}
return n;
}
/*计算随机迭代器计算位置差*/
template<class RandomAccessIterator> //vector,array
inline
iterator<InputIterator>::difference_type
distance(InputIterator first,InputIterator last,random_access_iterator_tag)
{
return last-first;
}
标准库除去onput_iterator还有四种,这里为啥只写了两种呢?
其实存在一种继承关系 is-a
input_iterator_tag<-forward_iterator_tag<-bidirectional_iterator_tag<-random_access_iterator_tag
学过多态的就知道这里其实有四种,通过基类指针引用子类,所以中间两种迭代器就到了上面的第一个方法
其他算法还有advance前进n个位置,也要通过不同迭代器的种类来实现不同的方法
6.指针是否是迭代器呢?
可以被视成迭代器,但并不代表它是迭代器,你可以理解它为退化的迭代器
我们经常用的sort
可以看到sort标准库要求传的是随机型迭代器firs和last,但是我们在使用的时候可以通过传指针进行数组的排序,所以我们不难想出,在sort模板中可能有 T*,const T*的偏特化