C++ 迭代器
迭代器
迭代器类似于指针类型,也提供了对对象的间接访问。
就迭代器而言,其对象是容器中的元素或 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 个迭代器类别:
迭代器类别 | 特点 |
---|---|
输入迭代器 | 只读,不写;单遍扫描,只能递增 |
输出迭代器 | 只写,不读;单遍扫描,只能递增 |
前向迭代器 | 可读写;多遍扫描,只能递增 |
双向迭代器 | 可读写;多遍扫描,可递增递减 |
随机访问迭代器 | 可读写;多遍扫描,支持全部迭代器运算 |
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!