C++ 迭代器

2023-12-13 22:26:36

迭代器

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

获取迭代器

容器的迭代器类型

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

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

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>中还定义额外几种迭代器。这些迭代器包括以下几种:

  • 插入迭代器(insert iterator):这些迭代器被绑定到一个容器上,可用来向容器插入元素。
  • 流迭代器(stream iterator):这些迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流。
  • 反向迭代器(reverse iterator):这些迭代器向后而不是向前移动。除了 forward_list 之外的标准库容器都有反向迭代器。
  • 移动迭代器(move iterator):这些专用的迭代器不是拷贝其中的元素,而是移动它们。

插入迭代器

插入迭代器是一种迭代器适配器,它接受一个容器,生成一个迭代器,能实现向给定容器添加元素。当我们通过一个插入迭代器进行赋值时,该迭代器调用容器操作来给定容器的指定位置插入一个元素。
插入迭代器有三种类型,差异在于元素插入的位置:
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 */

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 << ' ';

反向迭代器

反向迭代器就是在容器中从尾元素反向移动的迭代器。
除了 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++ << ' ';
	}

泛型算法结构

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

迭代器类别特点
输入迭代器只读,不写;单遍扫描,只能递增
输出迭代器只写,不读;单遍扫描,只能递增
前向迭代器可读写;多遍扫描,只能递增
双向迭代器可读写;多遍扫描,可递增递减
随机访问迭代器可读写;多遍扫描,支持全部迭代器运算

文章来源:https://blog.csdn.net/w541541/article/details/134909394
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。