迭代器偏移——advance

2023-10-08 20:30
文章标签 偏移 迭代 advance

本文主要是介绍迭代器偏移——advance,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 场景

业务场景使用unordered_map,每次从指定位置n(n不大于unordered_map长度)开始往后遍历。由于unordered_map没有operator+=不能像vector一样通过+=偏移到指定位置。advance可以将迭代器偏移到n个位置。
本文简单探究一下advance不同迭代器实现过程是怎样,由于advance实现依赖迭代器类型,本文还会简单介绍一下iterator_category。

2. advance 用法介绍

http://www.cplusplus.com/reference/iterator/advance/?kw=advance

Advance iterator
template <class InputIterator, class Distance>void advance (InputIterator& it, Distance n);

Advances the iterator it by n element positions.
If it is a random-access iterator, the function uses just once operator+ or operator-. Otherwise, the function uses repeatedly the increase or decrease operator (operator++ or operator–) until n elements have been advanced.

Parameters

it
  Iterator to be advanced.
  InputIterator shall be at least an input iterator.
n
  Number of element positions to advance.
  This shall only be negative for random-access and bidirectional iterators.
  Distance shall be a numerical type able to represent distances between iterators of this type.

Return value

none

3. advance源码分析

3.1 源码查看
  /***  @brief A generalization of pointer arithmetic.*  @param  i  An input iterator.*  @param  n  The "delta" by which to change @p i.*  @return  Nothing.**  This increments @p i by @p n.  For bidirectional and random access*  iterators, @p n may be negative, in which case @p i is decremented.**  For random access iterators, this uses their @c + and @c - operations*  and are constant time.  For other %iterator classes they are linear time.*/template<typename _InputIterator, typename _Distance>inline voidadvance(_InputIterator& __i, _Distance __n){// concept requirements -- taken care of in __advancetypename iterator_traits<_InputIterator>::difference_type __d = __n;std::__advance(__i, __d, std::__iterator_category(__i));}

__advance 有两个特化

  template<typename _InputIterator, typename _Distance>inline void__advance(_InputIterator& __i, _Distance __n, input_iterator_tag){// concept requirements__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)while (__n--)++__i;}template<typename _BidirectionalIterator, typename _Distance>inline void__advance(_BidirectionalIterator& __i, _Distance __n,bidirectional_iterator_tag){// concept requirements__glibcxx_function_requires(_BidirectionalIteratorConcept<_BidirectionalIterator>)if (__n > 0)while (__n--)++__i;elsewhile (__n++)--__i;}template<typename _RandomAccessIterator, typename _Distance>inline void__advance(_RandomAccessIterator& __i, _Distance __n,random_access_iterator_tag){// concept requirements__glibcxx_function_requires(_RandomAccessIteratorConcept<_RandomAccessIterator>)__i += __n;}

从源码上可知,调用哪一个__advance 取决于 iterator_category 类型。

4. 迭代器类型 iterator_category

一共有5种iterator_category分别为:

  1. input_iterator:istream独有的迭代器。
  2. output_iterator:ostream独有的迭代器。
  3. forward_iterator:继承自input_iterator,单向走的迭代器,只能走一个,不能跳。如forward_list、单向list的hashtable
  4. bidirectional_iterator:继承自forward_iterator,双向走的迭代器,只能走一个,不能跳。如list、rb-tree、双向list的hashtable
  5. random_access_iterator:继承自bidirectional_iterator,可以跳的迭代器。如array、vector、deque。

使用stl我们一般不需要关系迭代器类型,但在stl源码中有很多地方使用到,这里我们只针在advance中迭代器类型起到的作用。

4.1 迭代器类型定义
  /***  @defgroup iterators Iterators*  These are empty types, used to distinguish different iterators.  The*  distinction is not made by what they contain, but simply by what they*  are.  Different underlying algorithms can then be used based on the*  different operations supported by different iterator types.*///@{ ///  Marking input iterators.struct input_iterator_tag { };///  Marking output iterators.struct output_iterator_tag { };/// Forward iterators support a superset of input iterator operations.struct forward_iterator_tag : public input_iterator_tag { };/// Bidirectional iterators support a superset of forward iterator/// operations.struct bidirectional_iterator_tag : public forward_iterator_tag { };/// Random-access iterators support a superset of bidirectional iterator/// operations.struct random_access_iterator_tag : public bidirectional_iterator_tag { };
4.2 几种容器迭代器类型定义
unorder_map迭代器类型:forward_iterator_tag

在这里插入图片描述

map迭代器类型:bidirectional_iterator_tag

在这里插入图片描述

vector迭代器类型:bidirectional_iterator_tag

vector 使用的是通用迭代器:random_access_iterator_tag
在这里插入图片描述

  /***  This class does nothing but define nested typedefs.  The general*  version simply "forwards" the nested typedefs from the Iterator*  argument.  Specialized versions for pointers and pointers-to-const*  provide tighter, more correct semantics.*/template<typename _Iterator>struct iterator_traits{typedef typename _Iterator::iterator_category iterator_category;typedef typename _Iterator::value_type        value_type;typedef typename _Iterator::difference_type   difference_type;typedef typename _Iterator::pointer           pointer;typedef typename _Iterator::reference         reference;};template<typename _Tp>struct iterator_traits<_Tp*>{typedef random_access_iterator_tag iterator_category;typedef _Tp                         value_type;typedef ptrdiff_t                   difference_type;typedef _Tp*                        pointer;typedef _Tp&                        reference;};template<typename _Tp>struct iterator_traits<const _Tp*>{typedef random_access_iterator_tag iterator_category;typedef _Tp                         value_type;typedef ptrdiff_t                   difference_type;typedef const _Tp*                  pointer;typedef const _Tp&                  reference;};

5. 例子

#include <iostream>
#include <unordered_map>
#include <vector>
#include <map>
using namespace std;// g++ advance.cpp  -std=c++0x -o aa
void test_umap()
{unordered_map<int, int> umap;int n1 = 100;for (size_t i = 0; i < n1; i++){umap[i] = i+1000000;}cout <<"test_umap bucket count: "<<umap.bucket_count()<<endl;// 表格重建for (size_t i = n1; i < n1 + 100000; i++){umap[i] = i+1000000;}cout <<"test_umap bucket count: "<<umap.bucket_count()<<endl;auto it = umap.begin();advance(it, 5);for(int i = 0; i < 5; ++i, ++it){cout<<it->first<<", "<<it->second<<endl;}
}void test_map()
{map<int, int> mp;for (size_t i = 0; i < 100; i++){mp[i] = i+1000000;}auto it = mp.begin();advance(it, 5);cout<<"\ntest_map"<<endl;for(int i = 0; i < 5; ++i, ++it){cout<<it->first<<", "<<it->second<<endl;}
}void test_vector()
{vector<int> vt;for (size_t i = 0; i < 100; i++){vt.push_back(i+1000000);}auto it = vt.begin();advance(it, 5);cout<<"\ntest_vector"<<endl;for(int i = 0; i < 5; ++i, ++it){cout<<*it<<endl;}
}int main()
{test_umap();test_map();test_vector();cout <<"\nmain end"<<endl;
}

运行结果

test_umap bucket count: 199
test_umap bucket count: 126271
5, 1000005
6, 1000006
7, 1000007
8, 1000008
9, 1000009test_map
5, 1000005
6, 1000006
7, 1000007
8, 1000008
9, 1000009test_vector
1000005
1000006
1000007
1000008
1000009main end

在这里插入图片描述

这篇关于迭代器偏移——advance的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/167808

相关文章

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

计算数组的斜率,偏移,R2

模拟Excel中的R2的计算。         public bool fnCheckRear_R2(List<double[]> lRear, int iMinRear, int iMaxRear, ref double dR2)         {             bool bResult = true;             int n = 0;             dou

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

六、我们应当怎样做需求调研:迭代

前面我一直在反复强调这样一个观点,需求分析不是一蹴而就的,是一个反复迭代的过程。它将从第一次需求分析开始,一直持续到整个项目生命周期。为什么这样说呢?让我们一起来分析分析。  在第一次的需求分析阶段,我们在一段时期内需要与客户进行反复地讨论,这个过程往往是这样一个反复循环的过程:需求捕获->需求整理->需求验证->再需求捕获••••••  需求捕获,就是我们与客户在一起开研讨会

多线程篇(阻塞队列- ArrayBlockingQueue)(持续更新迭代)

目录 一、源码分析 1. 先看个关系图 2. 构造方法 3. 核心属性 4. 核心功能 入队(放入数据) 出队(取出数据) 5. 总结 一、源码分析 1. 先看个关系图 PS:先看个关系图 ArrayBlockingQueue是最典型的有界阻塞队列,其内部是用数组存储元素的, 初始化时需要指定容量大小利用 ReentrantLock 实现线程安全。 在生产者

多线程篇(并发相关类- 原子操作类)(持续更新迭代)

目录 前言 一、原子变量操作类(AtomicLong为例) 1. 前言 2. 实例 二、JDK 8新增的原子操作类LongAdder 三、LongAccumulator类原理探究 前言 JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS实现的,相比使用锁实现原子性操作这在性能上有很大提高。 由于原子性操作类的原理都大致相同,这里讲解最简单的AtomicLo

PMP–一、二、三模–分类–14.敏捷–技巧–帮助团队交付价值的执行实践迭代和增量如何帮助交付工作产品

文章目录 技巧一模14.敏捷--实践--帮助团队交付价值的执行实践--持续集成--在不同层面测试、验收测试驱动开发 (ATDD) 、测试驱动开发和行为驱动开发、刺探 。90、 [单选] 敏捷项目的第一次迭代即将开始。发起人召集团队、Scrum主管、产品负责人和其他项目干系人参加启动会议。发起人强调需要在项目尽可能早的时候以最小的成本识别和应对项目风险。与会者实现发起人要求的最佳方式是什么?

设计模式-行为型模式-迭代器模式

1.迭代器模式的定义         迭代器模式提供一种对容器对象中的各个元素进行访问的方法,而不需要暴露该对象的内部细节;         在软件系统中,容器对象有两个职责:一是存储数据,二是遍历数据;从依赖性上看,前者是基本职责,而后者是可以变化的,又是可以分离的,因此可以将遍历数据的行为从容器中抽取出来,封装到迭代器对象中,由迭代器来提供遍历数据的行为,这将简化聚合对象的设计,更加符合单

java设计模式(行为型模式:状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式)

6,行为型模式 6.5 状态模式 6.5.1 概述 【例】通过按钮来控制一个电梯的状态,一个电梯有开门状态,关门状态,停止状态,运行状态。每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行时状态,就不能进行开门操作,而如果电梯门是停止状态,就可以执行开门操作。 类图如下: 代码如下: public interface ILift {//电梯的4个状态//