泛型编程之迭代器 Iterators

来源:互联网 发布:淘宝摄影服务市场入驻 编辑:程序博客网 时间:2024/06/16 17:51

接触迭代器主要是在接触和使用STL时候开始的。作为泛型编程的良好实践,STL的迭代器有着非常显著的代表性。

最初,我并不了解迭代器的作用,甚至一直很排斥使用它。但随着逐步开始了解STL,慢慢开始了解了迭代器的意义以及重要性。本文主要是就自己所学所了解做一个简单的整理。本文内容参考整理自《泛型编程与STL》。

一、迭代器的重要性

迭代器,又称作泛型指针。顾名思义,迭代器就是模仿指针来实现的。有些情况,它就是指针。比方说vector,由于它使用的是一整块连续空间,所以直接拿其指针就可以作为随机迭代器使用,是非常强力的。

那么为什么我们不直接用指针,而一定要弄一个迭代器出来呢?

因为它是数据结构与算法之间的重要接口。以STL中的算法find为例,它要求可以遍历某个数据结构并读取其中元素的值。如果我们只提供指针给它,那么它针对vector要写一个算法,针对list链表又要重新写一个算法。而实际上,算法对这两种数据结构的要求是相同的:按某个线性顺序遍历并读取元素。因此我们可以把vector和list的遍历的这种特性抽象出来,做成迭代器,这样算法就可以保证它的通用性和简洁性、有效性。对于vector的抽象很简单,只需要把其指针拿出来直接用即可。但对于list,我们就需要在iterator类中对++操作、*操作进行运算符重载,以模仿指针行为。

对于不同的数据结构,迭代器的复杂程度是截然不同的,而能实现的功能也是不同的。与此同时,我们也要注意到不同的算法对迭代器的要求也是不同的。因此,我们要了解迭代器的分类,以及不同的迭代器和什么样的算法是匹配的,这样才能准确的使用STL库,甚至设计自己的迭代器。

二、迭代器的分类

迭代器总的来说,主要有五种不同的迭代器类别:Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator,Random Access Iterator。此处暂且不谈Trivial Iterator,其存在的目的是为了用来厘清其他Iterator concepts的定义。

1,Input Iterator

①作为一般的指针来看的时候,有三种取值,可取值指针,跨越尾端指针,NULL。

②可以比较相等性。(比较大小是无意义的)

③可以被复制或被赋值,即可以读取出来。

④可以提领对象,即*运算是有意的。(*p)

⑤支持++操作,指向下一个对象。(++p,p++)

⑥不能改动其提领的结果。(即*p=x不一定有效)

⑦遍历时,不保证之前的迭代器的有效性。单回(single pass)算法适用。

事实上,这个名字暗示了我们用这个迭代器读取下一个值之后,上一个会消失。一个很典型的代表就是STL中的Input Iterator class istream_iterator,可以很简单地从input stream读进数据。

2,Output Iterator

与Input Iterator类似,只是由读取变为了写入。

①同上,除了跨越尾端指针这处。

②同上

③可以复制和赋值,即可以写入。

④可以提领对象方式复制。(*p=x)

⑤同上

⑥不能读取其值。(不能用x=*p)

⑦同上

和上面类似,在STL中一个很典型的代表就是ostream_iterator,可以很简单地写入数据到ostream。

3,Forward Iterator

①同时具备读写性

②可以同时对多个元素操作(支持multipass算法)

单向迭代器在上面两种迭代器上进行了更强的功能约束。在单向遍历上,我们更常用这种迭代器。以stl的find为例,虽然它的要求只是Input Iterator即可以使用,但我们更多的时候是希望查找并且不改变原有数据的状态的,所以我们多数时候使用的都是单向迭代器。

4,Bidirectional Iterator

①支持双向移动,重载--运算(--p.p--)

相对上一个增强了反向移动的功能。双向链表就是这样的迭代器。

5,Random Access Iterator

①支持加法、减法(p+n,p-n)

②支持下表运算(p[n])

③支持相减(p1-p2)

④支持比较前后次序(p1<p2)

随机迭代器是最强化的迭代器,功能的约束也最高,它实现了所有的指针运算。vector的迭代器就属于这类。这种迭代器对于STL中的sort这类算法非常重要,因为sort中的排序算法要求能随机读取数据。

三、迭代器之间的关系

定义Refinement(精炼、强化):如果concept C2提供concept C1的所有功能,再加上其他可能的额外功能,就说C2是C1 的refinement。

性质:

1,Reflexivity(自反性)。每个concept C 都是自身的一个refinement。

2,Containment(涵盖性)。如果x 是concept C2的一个model,而C2是C1的一个refinement,那么x必然是C1的一个model。

3,Transitivity(传递性)。如果C3是C2的一个refinement,C2是C1的一个refinement,那么C3一定是C1的refinement。


四、部分常用数据结构、算法与迭代器

下面简单的介绍一下我们平时常用的一些数据结构的迭代器类型。

序列式容器:

vector    提供随机迭代器(插入、删除元素都会导致迭代器失效)

list          提供单向迭代器(插入不会使迭代器失效,删除非指向元素不会使迭代器失效)

deque   提供随机迭代器(插入、删除元素都会导致迭代器失效)

string     提供随机迭代器(插入、删除元素都会导致迭代器失效)

关联式容器:

set        提供双向迭代器 (如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。)

map     提供双向迭代器(迭代器只能修改value,不能修改key的值。如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。)

其他容器:

stack、queue、bitset  不能遍历。


不改变操作对象内容的算法:

Input Iterator:find,find_if ,find_first_of,count,,count_if,for_each,equal,mismatch,lexicographical_compare,

Forward Iterator:adjacent_find,search,find_end,search_n,min_element,max_element

会改变操作对象内容的算法:

Input Iterator :accumulate,inner_product

Output Iterator: fill_n,generate_n,unique_copy

Input Iterator & Output Iterator: copy,transform,replace_copy,replace_copy_if,remove_copy,remove_copy_if,partial_sum,adjacent_difference

Forward Iterator:swap_ranges,replace,replace_if,fill,generate,remove,remove_if,unique,rotate,rotate_copy,stable_partition

Bidirectional Iterator:copy_backward,reverse,reverse_copy,next_permutation,prev_permutation,partition

Random Access Iterator:random_shuffle

Input Iterator &Random Access Iterator:random_sample

Forward Iterator &Random Access Iterator:random_sample_n

排序和查找:

Input Iterator:includes

Input Iterator & Output Iterator: merge,set_union,set_intersection,set_difference,set_symmetric_difference

Forward Iterator:is_sorted,binary_search,lower_bound,upper_bound,equal_range

Bidirectional Iterator: inplace_merge

Random Access Iterator:sort,stable_sort,partial_sort,nth_element,make_heap,push_heap,,pop_heap,sort_heap,is_heap

Input Iterator &Random Access Iterator:partial_sort_copy

五、最后

整理了这么多,但依然有很多关于迭代器的概念没有整理到。比方说迭代器的其他概念:const Iterator,reverse Iterator等。还有迭代器特征、相关型别的问题也没有进行深入学习整理,留待以后有空再做整理。

0 0