C++ Primer 笔记十三 迭代器介绍

迭代器介绍


迭代器也是一种类型,用于访问容器中的元素或者在元素之间移动,有点类似于指针。
迭代器是比下标运算符更通用的访问机制,因为所有标准库容器都可以使用迭代器,但是其中只有少数几种才同时支持下标运算符。
有效的迭代器应该指向某个元素或者容器中尾元素的下一个位置;其他情况都属于无效迭代器。

begin 和 end 运算符
指针可以通过取地址符(&)获取,迭代器可以通过成员函数 beginend 来获得。

vector<int> ivec;
// 返回指向第一个元素的迭代器;若容器为空,返回尾后迭代器
auto b = ivec.begin();
// 返回指向尾元素下一个位置的迭代器(尾后迭代器)
auto e = ivec.end();

标准库类型使用 iteratorconst_iterator 来表示迭代器的类型。iterator 的对象可读可写,const_iterator 类似与常量指针,只可以读,不可写。常量对象只能使用 const_iterator,非常量对象可以使用 iterator 也可以使用 const_iterator

beginend 返回的具体类型由对象是否是常量决定。如果是常量,则返回 const_iterator,否则,返回 iterator。C++11 引入了 cbegincend 用来获取 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

类似于指针,解引用一个有效的迭代器(非尾后迭代器)可以获取迭代器所指向的元素。试图解引用非法迭代器或者尾后迭代器的行为都是未定义的。

如果容器为空,则 beginend 都返回尾后迭代器,据此也可以判断容器是否为空。

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!
$ 

_(´ω` ∠)_

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值