【笔记】《C++Primer》chapter10 泛型算法

10.1 概述

10.2 初识泛型算法

1. 只读算法

int sum = accumulate(vec.cbegin(), vec.cend(), 0);

accumulate 的第三个参数的类型决定了函数中使用哪个加法运算符以及返回值的类型

算法和元素类型
string sum = accumulate(v.cbegin(), v.cend(), "");// error, ""是const char *类型,不能执行+运算符
操作两个序列的算法

equal用于确定两个序列是否保存相同的值,它将第一个序列中的每个元素与第二个序列中的对应元素进行比较

如果所有对应元素都相等,则返回true,否则返回false

equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());

2. 写容器元素的算法

算法不检查写操作
fill_n(dest, n, val); // 如果dest的可用容量小于n那么结果是未定义的
介绍back_inserter

back_inserter(vec)返回一个迭代器,解引用这个迭代器并且赋值将向vec执行push_back,使值被推入容器末尾

vector<int> vec;
auto it = back_inserter(vec);
*it = 42;
拷贝算法
int a1[] = {0, 1, 2, 3, 4, ,5 ,6 ,7 ,8 ,9 ,0};
int a2[sizeof(a1)/sizeof(*a1)];
auto ret = copy(ai, begin(a1), end(a1), a2);

3. 重排容器元素的算法

消除重复单词
void elimDups(vector<string> &words){
    // 按字典排序words,一边查找重复单词
    sort(words.begin(), words.end());
    // unique重排输入范围,使得每个单词只出现一次
    // 排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
    auto end_unique = unique(words.begin(), words.end());
    // 使用向量操作erase删除重复单词
    words.erase(end_unique, words.end());
}

标准库算法对迭代器而不是容器操作,因此并不能直接添加和删除元素

使用容器操作删除元素

10.3 定制操作

1. 向算法传递函数

bool isShorter(const string &s1, const string &s2){
    if (s1.size() == s2.size()) return s1 < s2;
    else return s1.size() < s2.size();
}
int main(){
    sort(words.begin(), words.end(), isShorter);
}
排序算法
#include <algorithm>
using std::sort; using std::for_each;

#include <functional>
using std::bind; 
using namespace std::placeholders;

#include <string>
using std::string;

#include <vector>
using std::vector; 

#include <iostream>
using std::cin; using std::cout; using std::endl; 

// comparison function to be used to sort by word length
bool isShorter(const string &s1, const string &s2)
{
    return s1.size() < s2.size();
}

bool LT(const string &s1, const string &s2)
{
	return s1 < s2;
}

void print(const vector<string> &words)
{
	for_each(words.begin(), words.end(),
	        [](const string &s) { cout << s << " "; });
	cout << endl;
}

int main()
{
    vector<string> words;

    // copy contents of each book into a single vector
    string next_word;
    while (cin >> next_word) {
        // insert next book's contents at end of words
        words.push_back(next_word);
    }
	print(words);

	vector<string> cpy = words; // save the original data

	// uses string < to compare elements
	// sort and print the vector
	sort(words.begin(), words.end());

	words = cpy;  // return to the original data
	// uses the LT function to compare elements
	// should have the same output as the previous sort
	sort(words.begin(), words.end(), LT);
    print(words);

	words = cpy;  // return to the original data

	// eliminate duplicates
	sort(words.begin(), words.end());
	auto it = unique(words.begin(), words.end());
	words.erase(it, words.end());

	// sort by length using a function
	stable_sort(words.begin(), words.end(), isShorter);  
    print(words);

	words = cpy; // return to the original data
	// sort the original input on word length, shortest to longest
	sort(words.begin(), words.end(), isShorter);  
    print(words);

	// use bind to invert isShorter to sort longest to shortest
	sort(words.begin(), words.end(), bind(isShorter, _2, _1));  
    print(words);

	return 0;
}

2. lambda表达式

[capture list](parameter list) -> return type {function body}

capture list是捕获列表,用于捕获当前作用域中的局部变量,使其可用于lambda的函数体

如果lambda 的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void

捕获列表只用于局部非static变量,lambda可以直接使用局部static和所在函数之外声明的名字

3. lamnda捕获和返回

#include <vector>
#include <string>
#include <iostream>
using std::cout; using std::endl; using std::vector; using std::string;

// five functions illustrating different aspects of lambda expressions
void fcn1()
{
	size_t v1 = 42;  // local variable
	// copies v1 into the callable object named f
	auto f = [v1] { return v1; };
	v1 = 0;
	auto j = f(); // j is 42; f stored a copy of v1 when we created it
	cout << j << endl;
}

void fcn2()
{
	size_t v1 = 42;  // local variable
	// the object f2 contains a reference to v1 
	auto f2 = [&v1] { return v1; };
	v1 = 0;
	auto j = f2(); // j is 0; f2 refers to v1; it doesn't store it
	cout << j << endl;
}

void fcn3()
{
	size_t v1 = 42;  // local variable
	// f can change the value of the variables it captures
	auto f = [v1] () mutable { return ++v1; };
	v1 = 0;
	auto j = f(); // j is 43
	cout << j << endl;
}

void fcn4()
{
	size_t v1 = 42;  // local variable
	// v1 is a reference to a nonconst variable
	// we can change that variable through the reference inside f2
	auto f2 = [&v1] { return ++v1; };
	v1 = 0;
	auto j = f2(); // j is 1
	cout << j << endl;
}

void fcn5()
{
    size_t v1 = 42;
	// p is a const pointer to v1
    size_t* const p = &v1;
	// increments v1, the objet to which p points
    auto f = [p]() { return ++*p; };
    auto j = f();  // returns incremented value of *p
    cout << v1 << " " << j << endl; // prints 43 43
    v1 = 0;
    j = f();       // returns incremented value of *p
    cout << v1 << " " << j << endl; // prints 1 1
}


int main()
{
	fcn1();
	fcn2();
	fcn3();
	fcn4();
	fcn5();
	return 0;
}

编译运行:

[root@localhost 10]# ./lambda.exe 
42
0
43
1
43 43
1 1

image-20201022105652020

4. 参数绑定

标准库bind函数
auto newCallable = bind(callable, arg_list);

arg_list是参数列表,当newCallable被调用时,这些参数会被传递给它

arg_list中可能含有_n这种形适的名字,它们称为占位符,其中_1为newCallable的第一个参数,_2为第二个参数,最多9个占位符

#include <algorithm>
using std::for_each;

#include <functional>
using std::bind; using namespace std::placeholders;
using std::ref;

#include <iterator>
using std::istream_iterator;

#include <vector>
using std::vector;

#include <string>
using std::string; 

#include <iostream>
using std::cout; using std::cin; using std::endl;
using std::ostream; 

#include <fstream>
using std::ifstream; using std::ofstream; 

ostream &print(ostream &os, const string &s, char c)
{
	return os << s << c;
}

int main()
{
	string s;
	vector<string> words;
	while (cin >> s)
		words.push_back(s);

	for_each(words.begin(), words.end(), 
	         bind(print, ref(cout), _1, ' '));
	cout << endl;

	ofstream os("data/outFile1");
	for_each(words.begin(), words.end(), 
	         bind(print, ref(os), _1, ' '));
	os << endl;

	ifstream is("data/outFile1");
	istream_iterator<string> in(is), eof;
	for_each(in, eof, bind(print, ref(cout), _1, '\n'));
	cout << endl;

	return 0;
}

10.4 再探迭代器

除了为每个容器定义的迭代器之外,标准库iterator中还定义了额外几种迭代器:

  • 插入迭代器(insert itrator)
  • 流迭代器(stream iterator)
  • 反向迭代器(reverse iterator)
  • 移动迭代器(move iterator)

1. 插入迭代器

image-20201022155051703

  • back_inserter创建一个使用push_back的迭代器
  • front_inserter创建一个使用push_front的迭代器
  • inserter创建一个insert迭代器,此函数接收第二个参数,是指向给定容器的迭代器,元素将被插入到迭代器指定位置之前

2. iostream迭代器

#include <algorithm>
using std::copy; using std::sort; using std::unique_copy;

#include <vector>
using std::vector;

#include <string>
using std::string;

#include <iterator>
using std::istream_iterator; using std::ostream_iterator;

#include <fstream>
using std::ofstream;

#include <iostream>
using std::cin; using std::cout; using std::endl;

int main()
{
    istream_iterator<int> int_it(cin); // reads ints from cin
    istream_iterator<int> int_eof;     // end iterator value
	vector<int> v(int_it, int_eof);    // initialize v by reading cin

    sort(v.begin(), v.end());
    ostream_iterator<int> out(cout, " "); // write ints to cout
    unique_copy(v.begin(), v.end(), out); // write unique elements to cout
    cout << endl;                         // write a newline after the output
	ofstream out_file("data/outFile2");   // writes int to named file
	ostream_iterator<int> out_iter(out_file, " ");
	copy(v.begin(), v.end(), out_iter); 
	out_file << endl;  // write a newline at end of the file
    return 0;
}

3. 反向迭代器

除了forward_list之外,其他容器都支持反向迭代器,我们可以通过调用rbegin、rend、crbegin、crend成员函数来获取反向迭代器

10.5 泛型算法结构

image-20201022200744745

1. 5类迭代器

10.6 特定容器算法

posted @ 2021-04-24 11:05  汉森伯逸  阅读(51)  评论(0编辑  收藏  举报