C++ STL迭代器

迭代器

迭代器类似于指针类型,也提供了对对象的间接访问。
就迭代器而言,其对象是容器中的元素或 string 对象中的字符。

获取迭代器

容器的迭代器类型

使用作用域运算符来说明我们希望使用的类型成员;例:string::iterator iter;

类型别名功能
iterator此容器类型的迭代器
const_iterator可以读取元素,但不能修改元素的迭代器类型
diffreence_type带符号整数类型,足够保存两个迭代器之间的距离

begin 和 end 成员

和指针不同的是,获取迭代器不适用取地址运算符,有迭代器的类型,同时拥有返回迭代器
的成员函数。
成员函数 begin 生成指向容器中的第一个元素的迭代器。
成员函数 end 生成指向容器中的尾元素之后位置的迭代器(简称尾后迭代器)。

/*获取迭代器,使用 auto 推断迭代器的类型*/
	string str{ "Hello World" };
	auto iter_b = str.begin(); 
	auto iter_e = str.end();

begin 和 end 有多个版本:带 r 的版本返回反向迭代器,以 c 开头的版本则返回 const 迭代器。
可以将一个普通的 iterator 转换为对应的 const_iterator,但反之不行。
以 c 开头的版本是C++新标准引入的,用以支持 auto 与 begin 和 end 函数结合使用。

迭代器运算

解引用

可以通过解引用迭代器来获取它所指向的元素。

	string str{ "Hello World" };
	auto iter = str.begin();
	cout << *iter << endl; //输出 H 

试图解引用一个非法的迭代器或者尾后迭代器结果都是未定义的。

算数运算

迭代器加上或减去整数

迭代器加上(或减去)一个整数值扔得一个迭代器,迭代器指示的新位置与原来相比向前移动了若干个元素。

	string str{ "Hello World" };
	auto iter = str.begin();
	iter = iter + 4;
	cout << *iter << endl;       // 输出 o
	cout << *(iter - 3) << endl; // 输出 e

迭代器支持加法(或减法)的复合赋值语句

	string str{ "Hello World" };
	auto iter = str.begin();
	iter +=  4;
	cout << *iter << endl; // 输出 o
	iter -= 3;
	cout << *iter << endl; // 输出 e

迭代器支持递增(或递减运算符),表示迭代器指向下一个元素。

	string str{ "Hello World" };
	auto iter = str.begin();
	/* 将迭代器向前移动一个元素,然后输出移动后的值 */ 
	cout << *++iter << endl;  // 输出 e
	/* 将迭代器向后移动一个元素,然后输出移动后的值 */ 
	cout << *--iter << endl;  // 输出 H
两个迭代器可以相减

如果两个迭代器指向同一个容器,则两个迭代器相减的结果是它们之间的距离。

	string str{ "Hello World" };
	auto iter = str.begin();
	auto iter_b = iter + 1;
	auto iter_e = iter + 4;
	cout << (iter_e - iter_b) << endl; //输出 3
两个迭代器可以比较

如果两个迭代器指向同一个容器,则可以进行比较;指向前面元素的迭代器小于指向后面元素的迭代器。

	string str{ "Hello World" };
	auto iter = str.begin();
	auto iter_b = iter + 1;
	auto iter_e = iter +  4;
	cout << (iter_b  < iter_e) << endl; //输出 1

如果两个迭代器相等,则两个迭代器指向同一个元素,或者它们是同一个容器的尾后迭代器。

使用迭代器遍历容器
	string str{ "Hello World" };
	auto it_c = str.cbegin();
	for (auto iter = str.begin(); iter < it_c + str.size(); iter += 1)
	{
		cout << *iter;
	}

迭代器范围

一个迭代器范围(iterator range)由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者尾元素之后的位置(one past the last element)。
迭代器范围也被称为左闭合区间(left-inclusive interval),其标准数学描述为:[begin end)
标准库使用左闭合范围是因为这种范围有三种方便的性质。
假定 begin 和 end 构成一个合法的迭代器范围,则

  • 如果 begin 和 end 相等,则范围为空。
  • 如果 begin 和 end 不相等,则范围至少包含一个元素,且 begin 指向该范围中的第一个元素。
  • 我们可以对 begin 递增若干次,使得begin == end
使用迭代器遍历容器
	string str{ "Hello World" };
	auto iter = str.begin();
	while ( iter != str.cend() )
	{
		cout << *iter++ << ' ';
	}

使用!=而不是<判断是否到达尾序列;部分原因是,只有随机访问迭代器才支持<运算符。

迭代器适配器

<iterator>中,标准库提供了迭代器适配器,能从一个给定的迭代器类型生成有用的相关迭代器类型:

类型别名功能
reverse_iterator反向遍历
back_insert_iterator在尾部插入
front_insert_iterator在头部插入
insert_iterator在任意位置插入
move_iterator移动而不是拷贝
raw_storage_iterator写入未初始化的存储空间

反向迭代器

除了 forward_list 之外的标准库容器都有反向迭代器。
反向迭代器就是在容器中从尾元素反向移动的迭代器。
成员函数 rbegin 返回指向容器尾元素的迭代器。
成员函数 rend 返回指向容器首元素之前位置的迭代器。
反向迭代器迭代器也有 const 版本,即 crbegin 和 crend。

使用反向迭代器逆序遍历容器
	deque <char> D{ 'A','B','C','D','E' };
	auto it = D.crbegin();
	while (it != D.crend())
	{
		cout << *it++ << ' ';
	}

插入迭代器

插入迭代器是一种迭代器适配器,它接受一个容器,生成一个迭代器,能实现向给定容器添加元素。
当我们通过一个插入迭代器进行赋值时,该迭代器调用容器操作来给定容器的指定位置插入一个元素。
插入迭代器有三种类型,差异在于元素插入的位置:
函数 back_inserter 用 push_back 在序列尾元素之后插入新值。

	deque <char> D{ 'F','G','H' };
	auto it = back_inserter(D);
	/*尾后插入字母 A B C D E */
	for (char i = 'A'; i < 'F'; ++i)
	{
		*it = i; //等价于 D.push_back( i );
	}
/* 队列内的元素变为:F G H A B C D E */

函数 front_inserter 用 push_front 在序列首元素之前插入新值。

	deque <char> D{ 'F','G','H' };
	auto it = front_inserter(D);
	/*首前插入字母 A B C D E */
	for (char i = 'A'; i < 'F'; ++i)
	{
		*it = i; //等价于 D.push_front( i );
	}
/* 队列内的元素变为:E D C B A F G H */

函数 inserter 用 insert 在指向的元素之前插入新值。
此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器;元素被插入到给定迭代器所表示的元素之前。

	deque <char> D{ 'F','G','H' };
	auto it = inserter ( D ,D.begin() );
	for (char i = 'A'; i < 'F'; ++i)
	{
		*it = i; //等价于 it = D.insert(it,i); ++it; 其中,it = D.begin();
	}
/* 队列内的元素变为:A B C D E F G H */

移动迭代器

通过移动迭代器读取元素时会移动元素而非拷贝元素。
调用标准库的 make_move_inserter 函数将一个普通迭代器转换为一个移动迭代器。

mp = make_move_inserter(p);// mp 指向 p 所指向的元素;p 必须是一个输入迭代器

iostream 迭代器

虽然 iostream 类型不是容器,但标准库定义了可以用于这些 IO 类型对象的迭代器。
当创建一个流迭代器时,必须指定迭代器将要读写的对象类型。
istream_iterator 读取输入流

	deque <char> D;
	/*in_iter从输入流 cin 读取类型为 char 的值*/
	istream_iterator <char> in_iter( cin ); 
	istream_iterator <char> eof; //尾后迭代器
	while (in_iter != eof)
	{
		D.push_back( *in_iter++ ); //返回从流中读取的值,然后从流中读取下一个值
	}

ostream_iterator 向一个输出流写数据
我们可以提供一个(可选的)第二参数,它是一个字符串字面值,在输出每个元素后都会打印此字符串。
使用

	deque <char> D{ 'A','B','C','D','E' };
	ostream_iterator <char> out_iter (cout, " ");
	for (auto i : D)
		out_iter = i; //等价于cout << i << ' ';

范围访问函数

<iterator>中,标准库为容器提供了非成员版本的 begin() 和 end() 函数。

	int arr[] = { 1,3,5,7,9 };
	for (auto it = begin(arr); it < end(arr); ++it)
	{
		cout << *it << ' ';
	}

泛型算法结构

任何算法的最基本的特征是它要求其迭代器提供哪些操作。
算法所要求的迭代器操作可以分为 5 个迭代器类别:

迭代器类别特点
输入迭代器只读,不写;单遍扫描,只能递增
输出迭代器只写,不读;单遍扫描,只能递增
前向迭代器可读写;多遍扫描,只能递增
双向迭代器可读写;多遍扫描,可递增递减
随机访问迭代器可读写;多遍扫描,支持全部迭代器运算
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往昔的恒纳兰那

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值