《C++Primer》泛型算法

●  只读算法

int sum = accumulate(vec.begin(), vec.end(), 42);

将sum的值设置为vec的元素之和再加上42.容器内的元素类型必须与第三个实参的类型匹配,或者可转换为第三个实参的类型。

 

find_first_of

这个算法带有两对迭代器参数来标记两段元素范围,在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素,如果找不到匹配的元素,则返回第一个范围的end迭代器。这两个迭代器的类型必须精确匹配,只要这两个序列的元素可使用相等(==)操作符进行比较即可。

 

●  写容器元素的算法

fill(vec.begin(), vec.end(), 0);             //reset each element to 0

这个算法只会对输入范围内已存在的元素进行写入操作。

 

不检查写入操作的算法:

vector<int>   vec;   //empty vector

fill_n(vec.begin(), 10, 0);   //attempts to write to 10(nonexistent) elements in vec

这个fill_n函数的调用将带来灾难性的后果。我们执行要写入10个元素,但这些元素却不存在-vec是空的。

在没有元素的空容器上调用fill_n函数,将会出现严重的运行时错误!

 

引入back_inserter:

vector<int> vec;   //empty vector

fill_n(back_inserter(vec), 10, 0);   //appends 10 elements to vec

back_inserter creates an insert iterator that adds elements to vec

fill_n函数每写入一个值,都会通过back_inserter生成的插入迭代器实现。效果相当于在vec上调用push_back,在vec末尾添加10个元素,每个元素的值都是0.

 

写入到目标迭代器的算法:

vector<int> vec;   //empty vector

copy(ilist.begin(), ilist.end(),back_inserter(ivec));      //copy elements from ilist into ivec

copy从输入范围中读取元素,然后将它们赋值给目标ivec。

 

算法的_copy版本

replace(ilist.begin(), ilist.end(), 0, 42);     //replace any element with value of 0 by 42

这个调用将所有值为0的实例替换成42.如果不想改变原来的序列,则调用replace_copy。这个算法将接受第三个参数迭代器实参,指定保存调整后序列的目标位置。

vector<int> vec;

replace_copy(ilist.begin(), ilist.end(), back_inserter(vec),0,42);

调用函数后,ilist没有改变,vec储存ilist的一份副本,而ilist内所有的0在vec中都变成了42.

 

unique的使用:

该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器,表示无重复的值范围的结束。

注意:原容器的大小并没有改变,只是这些元素的顺序改变了,unique实际上并没有删除任何元素,而是将无重复的元素赋值到序列的前端,从而覆盖相邻的重复元素。unique返回的迭代器指向超出无重复元素范围末端的下一位置。

vector<string>::iterator endUnique = unique(words.begin(), words.end());

words.erase(endUnique, words.end());

 

●  插入迭代器

C++语言提供了三种插入迭代器,其差别在于插入元素的位置不同。

1.back_inserter,创建使用push_back实现插入的迭代器。

2.front_inserter,创建了使用push_front实现插入。

3.inserter,使用insert实现插入操作。除了所关联的容器外,inserter还带有第二个实参:指向插入起始位置的迭代器。

 

●  iostream迭代器

标准库定义的迭代器有很多种,istream_iterator用于读取输入流, ostream_iterator用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素序列。使用流迭代器时,可以用泛型算法从流对象读取数据(或将数据写到流对象)。

iostream迭代器的构造函数:

1. istream_iterator<T> in(strm);

创建从输入流strm读取T类型对象的istream_iterator对象

2. istream_iterator<T> in;

istream_iterator对象的超出末端迭代器。

3. ostream_iterator<T> out(strm);

创建将T类型的对象写到输出流strm的ostream_iterator对象

4. ostream_iterator<T> out(strm,delim);

创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分隔符。delim是以空字符结束的字符数组。

istream_iterator<int> cin_it(cin);//read ints from cin

istream_iterator<int> end_of_stream;//end iterator value(eof)

vector<int> vec(cin_it, end_of_stream);

sort(vec.begin(), vec.end());

ostream_iterator<int> output(cout, ” “);

unique_copy(vec.begin(), vec.end(), output);

 

in: 23 109 45 89 6 34 12 90 34 23 56 23 8 89 23

out:6 8 12 23 34 45 56 89 90 109

 

●  反向迭代器

  反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代
器,++ 运算将访问前一个元素,而 — 运算则访问下一个元素。

 

原vec:0,1,2…9

// reverse iterator of vector from back to front
vector<int>::reverse_iterator r_iter;
for (r_iter = vec.rbegin(); // binds r_iter to last element
      r_iter != vec.rend(); // rend refers 1 before 1st element
      ++r_iter) // decrements iterator one element
    cout << *r_iter << endl; // prints 9,8,7,…0

 

1.反向迭代器需要使用自减操作符
      从一个既支持 — 也支持 ++ 的迭代器就可以定义反向迭代器,这不用感到吃惊。毕竟,反向迭代器的目的是移动迭代器反向遍历序列。标准容器上的迭代器既支持自增运算,也支持自减运算。但是,流迭代器却不然,由于不能反向遍历流,因此流迭代器不能创建反向迭代器。

 

2.  如果要输出列表中最后一个单词,可使用反向迭代器:

// find last element in a comma-separated list
string::reverse_iterator rcomma = find(line.rbegin(), line.rend(), ‘,’);

因为此时传递的是 rbegin() 和 rend(),这个函数调用从 line 的最后一个字符开始往回搜索。当 find 完成时,如果列表中有逗号,那么 rcomma 指向其最后一个逗号,即指向反向搜索找到的第一个逗号。如果没有逗号,则 rcomma 的值为 line.rend()。
      在尝试输出所找到的单词时,有趣的事情发生了。直接尝试:

// wrong: will generate the word in reverse order
cout << string(line.rbegin(), rcomma) << endl;

会产生假的输出。例如,如果输入是:
      FIRST,MIDDLE,LAST
则将输出 TSAL!

使用反向迭代器时,以逆序从后向前处理 string对象。为了得到正确的输出,必须将反向迭代器 line.rbegin() 和 rcomma 转换为从前向后移动的普通迭代器。其实没必要转换 line.rbegin(),因为我们知道转换的结果必定是 line.end()。只需调用所有反向迭代器类型都提供的成员
函数 base 转换 rcomma 即可:

// ok: get a forward iterator and read to end of line
cout << string(rcomma.base(), line.end()) << endl;

 

image

●  const迭代器和const_iterator 迭代器

 

const 迭代器呢,你把它理解为 指向对象的 常指针,即指针是常量

const_iterator 迭代器呢,你把它理解为 指向 常对象 的指针,即指针指向的对象是常量

 

map、set和list类型提供双向迭代器,而string、vector和deque容器上定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator是输入迭代器,而ostream_iterator是输出迭代器。

 

BY:AloneMonkey

本文链接:http://www.alonemonkey.com/cplus-review-six.html