c++ STL深度探索之迭代器(算法和容器之间的桥梁)

3 篇文章 0 订阅

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*的偏特化 

  • 37
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++11STL中常用的迭代器算法有以下几个,分别是: 1. copy:将一个序列复制到另一个序列中。 2. reverse:将一个序列翻转。 3. sort:对一个序列进行排序。 4. unique:去除一个序列中的重复元素。 下面对每个算法进行详细介绍: 1. copy copy函数用于将一个序列复制到另一个序列中。其函数原型如下: ```c++ template <class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result); ``` 其中,first和last分别表示被复制序列的起始位置和结束位置(注意,end位置并不包括在序列内),result表示将要复制到的序列的起始位置。 例如,如果有两个整数数组a和b,我们想要将a中的元素复制到b中,可以这样写: ```c++ int a[] = {1, 2, 3, 4, 5}; int b[5]; copy(a, a + 5, b); ``` 这里,a和a+5分别表示数组a的起始位置和结束位置,b表示数组b的起始位置。复制后,数组b的内容为:{1, 2, 3, 4, 5}。 2. reverse reverse函数用于将一个序列翻转。其函数原型如下: ```c++ template <class BidirectionalIterator> void reverse(BidirectionalIterator first, BidirectionalIterator last); ``` 其中,first和last分别表示序列的起始位置和结束位置(注意,end位置并不包括在序列内)。 例如,如果有一个整数数组a,我们想要将其翻转,可以这样写: ```c++ int a[] = {1, 2, 3, 4, 5}; reverse(a, a + 5); ``` 这里,a和a+5分别表示数组的起始位置和结束位置。翻转后,数组a的内容为:{5, 4, 3, 2, 1}。 3. sort sort函数用于对一个序列进行排序。其函数原型如下: ```c++ template <class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last); ``` 其中,first和last分别表示序列的起始位置和结束位置(注意,end位置并不包括在序列内)。该函数只能用于随机访问迭代器。 例如,如果有一个整数数组a,我们想要将其排序,可以这样写: ```c++ int a[] = {5, 3, 1, 4, 2}; sort(a, a + 5); ``` 这里,a和a+5分别表示数组的起始位置和结束位置。排序后,数组a的内容为:{1, 2, 3, 4, 5}。 4. unique unique函数用于去除一个序列中的重复元素。其函数原型如下: ```c++ template <class ForwardIterator> ForwardIterator unique(ForwardIterator first, ForwardIterator last); ``` 其中,first和last分别表示序列的起始位置和结束位置(注意,end位置并不包括在序列内)。该函数只能用于前向迭代器。 例如,如果有一个整数数组a,其中有重复元素,我们想要去除重复元素,可以这样写: ```c++ int a[] = {1, 2, 2, 3, 3, 3, 4, 5, 5}; int* p = unique(a, a + 9); ``` 这里,a和a+9分别表示数组的起始位置和结束位置。去重后,数组a的前p-a个元素是不重复的,p之后的元素是无用的。这里,p指向的位置是a+5,即数组a的前5个元素是不重复的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值