迭代器介绍
迭代器也是一种类型,用于访问容器中的元素或者在元素之间移动,有点类似于指针。
迭代器是比下标运算符更通用的访问机制,因为所有标准库容器都可以使用迭代器,但是其中只有少数几种才同时支持下标运算符。
有效的迭代器应该指向某个元素或者容器中尾元素的下一个位置;其他情况都属于无效迭代器。
begin 和 end 运算符
指针可以通过取地址符(&
)获取,迭代器可以通过成员函数 begin
和 end
来获得。
vector<int> ivec;
// 返回指向第一个元素的迭代器;若容器为空,返回尾后迭代器
auto b = ivec.begin();
// 返回指向尾元素下一个位置的迭代器(尾后迭代器)
auto e = ivec.end();
标准库类型使用 iterator
和 const_iterator
来表示迭代器的类型。iterator
的对象可读可写,const_iterator
类似与常量指针,只可以读,不可写。常量对象只能使用 const_iterator
,非常量对象可以使用 iterator
也可以使用 const_iterator
。
begin
和 end
返回的具体类型由对象是否是常量决定。如果是常量,则返回 const_iterator
,否则,返回 iterator
。C++11 引入了 cbegin
和 cend
用来获取 const_iterator
,不论对象是否是常量,返回值都是 const_iterator
。
建议: 对于无需写操作的对象最好使用常量类型。
vector<int> ivec(20);
vector<int>::iterator ibeg = ivec.begin();
vector<int>::const_iterator ie = ivec.cend();
const vector<string> svec = {"abc", "EFG", "hijk"};
vector<string>::const_iterator sbeg = ivec.begin();
vector<string>::const_iterator se1 = ivec.cend();
// 下面操作会引发编译器报错
// conversion from ‘std::vector<std::basic_string<char> >::const_iterator
// to non-scalar type ‘std::vector<std::basic_string<char> >::iterator
vector<string>::iterator se2 = ivec.end();
迭代器的运算
*iter | 返回迭代器 iter 所指元素的引用 |
iter->men | 解引用 iter 并获取该元素的名为 men 的成员,等价于 (*iter).name |
++iter | 令 iter 指示容器中的下一个元素 |
--iter | 令 iter 指示容器中的上一个元素 |
iter1 == iter2 | 判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一个元素,或者它们是同一个容器的尾后迭代器,则相等;反之,不相等。 |
iter1 != iter2 |
类似于指针,解引用一个有效的迭代器(非尾后迭代器)可以获取迭代器所指向的元素。试图解引用非法迭代器或者尾后迭代器的行为都是未定义的。
如果容器为空,则 begin
和 end
都返回尾后迭代器,据此也可以判断容器是否为空。
string s("string");
if (s.begin() != s.end()) { // 非空判断
auto iter = s.begin();
}
迭代器的递增是将迭代器向前移动一个位置,因此可以使用迭代器来遍历容器中的元素。
一个练习(3.21):输出 vector 对象包含的元素的值。
// display.cc
#include <iostream>
#include <vector>
using std::vector;
using std::string;
using std::cout;
using std::endl;
template <typename T>
void display(vector<T> vec) {
int cnt = 0;
auto iter = vec.begin();
while (iter != vec.end()) {
++cnt;
cout << cnt << " :\t" << *iter << endl;
++iter;
}
cout << endl;
}
int main() {
vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{10};
vector<int> v5{10, 42};
vector<string> v6{10};
vector<string> v7{10, "hi"};
cout << "v1 : " << endl;
display(v1);
cout << "v2 : " << endl;
display(v2);
cout << "v3 : " << endl;
display(v3);
cout << "v4 : " << endl;
display(v4);
cout << "v5 : " << endl;
display(v5);
cout << "v6 : " << endl;
display(v6);
cout << "v7 : " << endl;
display(v7);
return 0;
}
【注】所有标准库容器的迭代器都定义了 == 和 !=,但是它们中的大多数都没有定义 < 运算符。
【注】 但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素,这会似的该对象的迭代器失效。
又一个练习(3.22) 假设用一个名为 text 的字符串向量存放文本文件中的数据,其中的元素或者是一句话或者是一个用于表示段落分隔的空字符串。首先把 text 第一段的内容全部改成大写形式,然后输出它。
// toupper.cc
#include <iostream>
#include <vector>
using std::vector;
using std::string;
using std::cout;
using std::endl;
int main() {
vector<string> text{"april is a dog's dream",
"",
"the soft grass is growing"};
for (auto viter = text.cbegin();
viter != text.cend() && !viter->empty(); ++viter) {
auto siter = viter->cbegin();
while (*siter) {
cout << (char)toupper(*siter);
++siter;
}
}
cout << endl;
return 0;
}
$ ./toupper.out
APRIL IS A DOG'S DREAM
迭代器运算
iter + n | 迭代器加上一个整数仍得一个迭代器,新位置与原来相比向前移动了若干个元素。 |
iter - n | 迭代器减去一个整数仍得一个迭代器,新位置与原来相比向后移动了若干个位置。 |
iter += n | 等价于 iter = iter + n; |
iter -= n | 等价于 iter = iter - n; |
iter1 - iter2 | 两个迭代器相减的结果是它们之间的距离,参与运算的两个迭代器必须指向同一个容器中的元素或者尾元素的下一个位置。所得结果类型为 `difference_type` 的带符号整型。 |
>、>=、<、<= | 如果迭代器指向的位置在另一个迭代器指向的位置之前,则说前者小于后者。参与运算的两个迭代器必须指向同一个容器中的元素或者尾元素的下一个位置。 |
使用迭代器进行二分搜索:
// binarysearch.cc
#include <iostream>
#include <vector>
using std::vector;
using std::string;
int main() {
vector<string> svec{"advantage", "binary",
"compensate", "detect", "enable",
"gamble", "holder", "intent",
"issue", "margin", "personality",
"recruit", "solution", "source",
"statement"};
auto ibeg = svec.begin();
auto iend = svec.end();
auto imid = ibeg + (iend - ibeg) / 2;
string inval;
std::cout << "Input : " ;
std::cin >> inval;
std::cout << std::endl;
while(ibeg <= iend && imid != svec.end()) {
if (*imid == inval) {
std::cout << "Pos: "
<< imid - svec.begin()
<< std::endl;
break;
} else if (*imid < inval) {
ibeg = imid + 1;
} else {
iend = imid - 1;
}
imid = ibeg + (iend - ibeg) / 2;
}
if (*imid != inval) {
std::cout << inval << " not found!" << std::endl;
}
return 0;
}
编译运行结果:
$ ./binarysearch.out
Input : holder
Pos: 6
$ ./binarysearch.out
Input : issue
Pos: 8
$ ./binarysearch.out
Input : mach
mach not found!
$
_(´ω` ∠)_