C++知识点28——使用C++标准库(再谈迭代器)

一、迭代器的种类

C++中的容器以及泛型算法会大量的使用迭代器

目前已经出现的迭代器有一下几种

1.输出迭代器 (OutputIterator)

输出迭代器类似于输出流(只能向输出流中写入数据),只能向输出迭代器中写入数据,输出迭代器的常用操作如下

 

2.输入迭代器 (InputIterator)

输入迭代器类似于输入流(变量只能读取输出流中的数据),只能向输出迭代器中写入数据,输入迭代器的常用操作如下

 

3.前向迭代器 (ForwardIterator)

加强版的输入迭代器,可以对前向迭代器进行赋值,如果一个前向迭代器不是const的,那么也具有输入迭代器的功能

C++标准库中的单向链表(forward_list)和无序容器的实现提供了前向迭代器,当然,无序容器也的实现也可以提供双向迭代器

 

4.双向迭代器 (BidirectionalIterator)

加强版的前向迭代器,提供了递减操作符,可以一步一步后退迭代器

在前向迭代器的基础上,新增的操作如下:

C++标准库中的双向链表(list)和关联容器的实现提供了双向迭代器

 

5.随机访问迭代器 (RandomAccessIterator)

加强版的双向迭代器,在双向迭代器的基础上增加了随机访问的能力,能够使迭代器增减某个偏移量,并且添加了比较操作

新增操作如下

C++标准库中的vector,deque,string以及指针提供了随机访问迭代器

 

使用随机访问迭代器时,需要注意不能让迭代器的位置超过end(),因为随机访问迭代器提供了前进n个元素的操作,所以在使用随机访问迭代器遍历容器的时,循环条件要写成it<container.end(),而不要写成it!=container.end(),因为迭代器作为循环变量有可能一次性前进n个元素,就像下图所示

上述五中迭代器,最最常用的是随机访问迭代器和双向迭代器,因为这两中迭代器由C++标准库中的主要容器提供使用,然后是前向迭代器,因为在使用迭代器时都是伴随这容器一起使用,所以输入输出迭代器一般情况用不到,在前面的博客中也会发现,输入输出迭代器一般用于指定容器成员函数和泛型算法函数的形参类型

 

二、五中迭代器的关系

1.所有前向,双向和随机访问迭代器也是有效的输入迭代器。

2.所有非const的前向,双向和随机访问迭代器也是有效的输出迭代器。

3.所有双向和随机访问迭代器也是有效的前向迭代器。

4.所有随机访问迭代器也是有效的双向迭代器。

5.就功能而言,随机访问迭代器是最完整的迭代器。 所有指针类型也是有效的随机访问迭代器。

 

上述五点中用图形来描述如下图

正是因为有上述关系,当我们使用C++标准库中以输入输出迭代器为形参的泛型算法函数或者容器的成员函数时,可以传入前向迭代器或者双向迭代器或者随机访问迭代器参数

同样,当我们使用C++标准库中以前向双向迭代器为形参的泛型算法函数或者容器的成员函数时,可以传入随机访问迭代器参数

当函数的返回值是一个输入或者输出迭代器,同样也可以用前向双向迭代器对象接收

 

三、迭代器相关的辅助函数

下面四个函数在使用前,要添加头文件 #include <iterator>

1.advance

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

该函数可将迭代器it的位置增加,其中对于双向和随机访问迭代器来说,n有可能是负数,此时迭代器的位置后退,n的类型一般来说是整形

注意:该函数并不检查迭代器it是否超过了end(),所以有可能导致迭代器失效,所以使用前要判断是否小于end()

 

示例

void advancetest()
{
	vector<int> v={1,2,3,4,5,6,7};
	vector<int>::iterator it=v.begin()+3;
	advance(it, 2);
	if (it<v.end()) {
		cout<<*it<<endl;
	}

	it=v.begin()+3;
	advance(it, -2);
	if (it<v.end()) {
		cout<<*it<<endl;
	}
}

 

2.next和prev

template <class ForwardIterator>
ForwardIterator next (ForwardIterator it, typename iterator_traits<ForwardIterator>::difference_type n = 1);

template <class BidirectionalIterator>
BidirectionalIterator prev (BidirectionalIterator it, typename iterator_traits<BidirectionalIterator>::difference_type n = 1);

next表示将迭代器的位置向前移动,如果it是一个双向迭代器或者是一个随机迭代器,那么n可以为负值,表示向后移动

prev表示将迭代器的位置向后移动,n可以为负值,表示向前移动

这两个函数依然不会保证迭代器有效,所以,调用者要自行保证这两个函数执行后,迭代器有效

 

示例

void nextprevtest()
{
	vector<int> v={1,2,3,4,5,6,7};
	vector<int>::iterator it=v.begin()+3;
	it=next(it, 2);
	if (it<v.end()) {
		cout<<*it<<endl;
	}
	it=prev(it,3);
	if (it<v.end()) {
		cout<<*it<<endl;
	}
}

 

3.distance

template<class InputIterator>
typename iterator_traits<InputIterator>::difference_type distance (InputIterator first, InputIterator last);

distance是计算并返回两个迭代器之间的距离,这两个迭代器必须指向同一个容器对象,如果first和last不是随机访问迭代器,那么,first前进必须能到达last,first必须在last之前或指向同一位置

 

示例

void distancetest()
{
	list<int> l={1,2,3,4,5,6,7};
	list<int>::iterator it1=l.begin();
	list<int>::iterator it2=l.end();
	int num=distance(it1,it2);
	cout<<num<<endl;
}

如果将第六行的代码改为int num=distance(it2,it1);,则会产生段错误

 

参考

《C++ Primer》

《C++标准库》

http://www.cplusplus.com/reference/iterator/

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值