使用迭代器
//迭代器是访问string对象的字符、vector对象的元素及其他容器元素的一种机制,所有标准库容器都可以使用迭代器,适用范围大于下标运算符
#include <iostream>
#include <vector>
#include <string>
#include <cctype>
#include <fstream>
using namespace::std;
int main()
{
//获取迭代器和指针不同,不使用取地址符,而是有迭代器的类型同时拥有返回迭代器的成员
//例如名为begin的成员负责返回指向第一个元素的迭代器
//名为end的成员负责返回指向容器(或string对象)“尾元素的下一个位置”的迭代器,这个迭代器指示的是容器的一个本不存在的“尾后”元素,简称尾后迭代器
//如果容器为空,begin和end返回的是同一个迭代器,都是尾后迭代器
vector<string> ss(10, "an");
auto b = ss.begin();
auto e = ss.end();
//迭代器运算符
//*iter 返回迭代器iter所指元素的引用
//iter->mem 解引用iter并获取该元素名为mem的成员,等价于(*iter).mem
//++iter 令iter指示容器的下一个元素
//--iter 令iter指示容器的上一个元素
//iter1 == iter2 判断两个迭代器是否相等,如果指示的是同一个元素或者都是同一个容器尾后迭代器则相等
//iter1 != iter2
//把string对象的第一个字母改成大写形式
string s = "some string";
if (s.begin() != s.end())//确保s非空
{
auto it = s.begin();
*it = toupper(*it);
}
//将迭代器从一个元素移动到另外一个元素,++,--
//注意,尾后迭代器并不实际指示某个元素,所以不能对其进行递增或解引用操作
//把string对象的第一个单词改写为大写形式
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
*it = toupper(*it);
//迭代器的类型
//我们无需知道迭代器的精确类型,就像string和vector的size_type成员到底是什么类型一样
vector<int>::iterator it;//it1可以读写
string::iterator it2;//it2可以读写
vector<int>::const_iterator it3;//it3只能读元素
string::const_iterator it4;//it4只能读元素
//begin和end运算符
//begin和end返回的具体类型由对象是否是常量决定,是常量,const_iterator,不是常量,iterator
//有些时候我们只需对对象进行读操作,C++11引入了cbegin()和cend()专门得到const_iterator,无论对象是否是常量
auto it5 = s.cbegin();
//结合解引用和成员访问操作
//解引用迭代器可以获得迭代器所指的对象,如果该对象的类型是类,我们可能需要进一步访问它的成员
(*it).empty();//正确
*it.empty();//错误,想要访问it的名为empty的成员,但it是迭代器,并没有empty成员
//为了简化上述表达式,C++定义了箭头运算符->,把解引用和成员访问两个操作结合在了一起
it->empty();//等价于(*it).empty
//把文本文件text.txt读入容器text
ifstream in("text.txt");
vector<string> text;
for (string a; in >> a;)
text.push_back(a);
//依次输入text的每一行直至遇到第一个空白行为止
for (auto it = text.cbegin();
it != text.cend() && !it->empty();
++it)
cout << *it << endl;
//某些对vector对象的操作会使迭代器失效
//vector对象可以动态的增长,但已知有两个限制
//不能在范围for循环中向vector对象添加元素
//任何改变vector容量的操作都有可能使该vector对象的迭代器失效
}
迭代器的运算
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
#include <fstream>
using namespace::std;
int main()
{
//iter + n 结果仍然是迭代器,迭代器指示的位置与原来相比向前移动了n个位置,结果最多到尾元素的下一个位置
//iter - n 同上,向后移动n个位置
//iter += n 将iter+n的结果赋给iter
//iter -= n 同上
//iter1 - iter2 结果是它们之间的距离,类型是名为difference_type的带符号整型数
//> >= < <= 关系运算符,位置在前的迭代器>位置在后的迭代器
//计算得到最接近vi中间元素的一个迭代器,它指向某vector对象中间位置的元素
//auto mid = vi.begin() + vi.size() / 2;
//处理vi前半部分元素
//if(it < mid){}
//使用迭代器进行二分搜索
//beg和end表示搜索范围
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end - beg) / 2;//初始状态下的中间点
//当元素尚未检查并且没找到smile时执行循环
int i = 0;
while (mid != end && *mid != sought) {
if (sought < *mid) //我们要找的元素在后半部分
end = mid; //调整搜索范围忽略后半部分
else //我们要找的元素在前半部分
beg = mid + 1; //在mid之后搜索
mid = beg + (end - beg) / 2;//新的中间点
}
}
练习
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
#include <fstream>
using namespace::std;
int main()
{
//练习3.24 使用迭代器重做下列练习
练习3.20 读入一组整数并存入一个vector对象,输出每对相邻整数的和
//vector<int> ive;
//int i;
//while (cin >> i)
// ive.push_back(i);
// for (i = 0; i < ive.size()-1; ++i)
// cout << ive[i] + ive[i + 1] << " " ;*/
// //改写程序,输出第1个和最后1个元素的和,第2个和倒数第2个元素的和,以此类推
//for (i = 0; i < ive.size() / 2; ++i)
// cout << ive[i] + ive[ive.size() - 1 - i] << " ";
//if (ive.size() % 2)
// cout << 2 * ive[ive.size() / 2];
vector<int> ive;
int i;
while (cin >> i)
ive.push_back(i);
//输出每对相邻整数的和
for (auto it = ive.begin(); it != ive.end(); ++it)
cout << *it + *(it + 1) << " ";
//输出第1个和最后1个元素的和,第2个和倒数第2个元素的和,以此类推
auto beg = ive.begin(), end = ive.end();
auto mid = beg + (end - beg) / 2;
while (beg <= mid && end >= mid) {
cout << *beg + *end << " ";
}
//练习3.25 使用迭代器重写下面程序
//vector<unsigned> scores(11, 0);
//unsigned grade;
//while (cin >> grade) {
// if (grade <= 100)//这里确认输入是否合理十分重要
// ++scores[grade / 10];//笔者觉得这很精妙简洁
//}
//for (auto c : scores)
// cout << c << " ";
vector<unsigned> rank(11, 0);//11个等级
unsigned grade;
while (cin >> grade)
if (grade <= 100)
(*(rank.begin() + grade / 10))++;
//输出
for (auto it = rank.begin(); it != rank.end(); ++it)
cout << *it << endl;
//练习3.26 二分搜索程序中,为什么用的是 mid = beg + (end - beg) / 2, 而非 mid = (beg + end) / 2 ; ?
//因为迭代器之间支持的运算只有’-’,而没有’+’。end-beg指相距若干元素,将它除以2之后与beg相加,表示移动到一beg与end中间的位置。
}