《C++primer(第五版)》学习之路-第十章:泛型算法

 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:[email protected]


10.1 概述


1.大多数算法都定义在头文件algorithm中。标准库还在文件numeric中定义了一组数值泛型算法。


10.2 初识泛型算法


1.

accumulate:定义在头文件numeric中。作用是对范围求和。

euqal:定义在头文件algorithm中。作用是判断给定两个区间是否相等。

fill:定义在头文件algorithm中。作用是对给定区间全部赋予某值。

fill_n:定义在头文件algorithm中。作用是对给定迭代器后的n个元素赋予某值。

back_inserter:定义在头文件iterator中。得到指向容器尾部的迭代器。

sort:定义在头文件algorithm中。对指定区间排序。

unique:定义在头文件algorithm中。“消除”重复项,返回指向不重复值范围末尾的迭代器。

erase:定义在头文件algorithm中。删除指定范围内的元素。


10.3 定制操作


1.谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。谓词分为:一元谓词和二元谓词。几元谓词接受几元参数。


2.可调用对象定义;对于一个对象或一个表达式,如果可以对其使用调用运算符,则称为可调用的;可调用的对象有:函数、函数指针、重载函数调用运算符的类和lambda表达式。
lambda表达式形式:
[capture list](parameter list)->return type{function body};
capture list是一个lambda所在函数中定义的局部变量的列表(通常为空);
return type、parameter list和function body分别表示返回类型、参数列表和函数体。


3.标准库bind函数

头文件:functional ;它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。
调用bind的形式:
auto newCallable=bind(callable, arg_list);
newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。arg_list中的参数可能包含形如_n的名字,_1是newCallable的第一个参数,_2为第二个参数,依次类推。


4.bind拷贝参数而不能拷贝ostream。我们可以使用ref函数。

函数ref返回一个对象,包含给定引用,此对象是可以拷贝的。标准库中海油一个cref函数,生成一个保存const引用的类。与bind一样,函数ref和cref也定义在头文件functional 中。


10.4 再探迭代器


1.

插入迭代器:这些迭代器被绑定到一个容器上,可用来向容器插入元素。

流迭代器:这些迭代器被绑定到输入或输出流上,可用来遍历所有关联的IO流。

反向迭代器:这些迭代器向后而不是向前移动。除了forward_list之外的标准库容器都有反向迭代器。

移动迭代器:这些专用的迭代器不是拷贝其中的元素,而是移动它们。


2.

back_inserter            创建一个使用push_back的迭代器

front_inserter            创建一个使用push_front的迭代器

inserter                      创建一个使用insert的迭代器。此函数接受第二个参数,这个参数必须是一个指向给定容器的

                                  迭代器。元素将插入到给定迭代器所表示的元素之前。


3.

istream_iterator操作

istream_iterator in(is)           in从输入流is读取类型为T的值

istream_iterator end;           读取类型为T的值的istream_iterator迭代器,表示尾后位置

in1 == in2                                   in1和in2必须读取相同类型。如果它们都是尾后迭代器,或绑定到相同

in1 != in2                                    的输入,则两者相等

*in                                               返回从流中读取的值

in->mem                                     与(*in).mem的含义相同

++in,in++                                   使用元素类型所定义的>>运算符从输入流中读取下一值。与以往一样,前置版本返回一个指向递增后迭代器的引用,后置版本返回旧值


4.

ostream_iterator操作

ostream_iterator out(os);         out将类型为T的值写到输出流os中

ostream_iterator out(os,d);      out将类型为T的值写到输出流os中,每个值后面都输出一个d。d指向一个空字符结尾的字符数组

out = val;                                        用<<运算符将val写入到out所绑定的ostream中。val的类型必须与out可写的类型兼容。

*out,++out,out++;                          这些运算符是存在的,但不对out做任何事情。每个运算符都返回out


10.5 泛型算法结构


1.迭代器类别

输入迭代器                只读,不写;单遍扫描,只能递增

输出迭代器                只写,不读;单遍扫描,只能递增

前向迭代器                可读写,多遍扫描,只能递增

双向迭代器                可读写,多遍扫描,可递增递减

随机访问迭代器         可读写,多遍扫描,支持全部迭代器运算


10.6 特定容器算法


1.

list和forward_list成员函数版本的算法

lst.merga(lst2)            

lst.megra(lst2,comp)    将来自lst2的元素合并入lst。lst和lst2都必须是有序的。元素将从lst2中删除。在合并之后,lst2变成空。第一个版本使用<运算符;第二个版本使用给定的比较操作。

lst.remove(val)            

lst.remove_if(pred)      调用erase删除掉与给定值相等(==)或令一元谓词为真的每个元素

lst.reverse()                 反转lst中元素的顺序

lst.sort()                       

lst.sort(comp)               使用<或给定比较操作排序元素

lst.unique()        

lst.unique(pred)            调用erase删除统一个值的连续拷贝。第一个版本使用==;第二个版本使用给定的二元谓词


2.

list和forward_list的splice成员函数的参数

lst.splice(args)或flst.splice_after(args)

(p,lst2)         p是一个指向lst中元素的迭代器,或一个指向flst首前位置的迭代器。函数将lst2的所有元素移动到lst中p之前的位置或是flst中p之后的位置。将元素从lst2中删除。lst2的类型必须与lst或flst相同,且不能是同一个链表。

(p,lst2,p2)    p2是一个指向lst2中位置的有效迭代器。将p2指向的元素移动到lst中,或将p2之后的元素移动到flst中。lst2可以是与lst或flst相同的链表。

(p,lst2,b,e)   b和e必须表示lst2中的合法范围。将给定范围中的元素从lst2移动到lst或flst。lst2与lst(或flst)可以是相同的链表,但p不能指向给定范围中元素。



PS:部分练习答案


练习10.1 & 10.2

#include 
#include 
#include 
#include 
#include 

int main()
{
	std::vector vec = {1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,5};
	std::cout << "ex 10.1: " << std::count(vec.cbegin(),vec.cend(),5) << "times" << std::endl;
	
	std::list lst = {"a","aa","aa","aa"};
	std::cout << "ex 10.2: " << std::count(lst.cbegin(),lst.cend(),"aa") << "times" << std::endl;
	
	return 0;
}

练习10.3 & 10.4

#include 
#include 
#include 
#include 
#include 

int main()
{
	std::vector ivec = {1,2,3,4,5};
	std::cout << "ex 10.3: " << std::accumulate(ivec.cbegin(),ivec.cend(),0) << std::endl;
	
	std::vector dvec = {1.1,2.2,3.3,4.4,5.5};
	std::cout << "ex 10.4: " << std::accumulate(dvec.cbegin(),dvec.cend(),0) << std::endl;
	std::cout << "ex 10.4: " << std::accumulate(dvec.cbegin(),dvec.cend(),double(0)) << std::endl;
	
	return 0;
}

练习10.5

#include 
#include 
#include 
#include 

int main()
{
	std::vector roster1{"one","two","three"};
	std::list roster2{"one","two","three","four","five"};
	
	std::cout << std::equal(roster1.cbegin(),roster1.cend(),roster2.cbegin()) << std::endl;
}

练习10.6

#include 
#include 
#include 

int main()
{
	std::vector ivec {1,2,3,4,5,6,7,8,9,10};
	std::fill_n(ivec.begin(),ivec.size(),0);
	for(auto i: ivec)
		std::cout << i << " ";
	std::cout << std::endl;
}

练习10.7

a.运行错误,改正为

vector vec;
list lst;
int i;
while (cin >> i) lst.push_back(i);
vec.resize(lst.size());
copy(lst.cbegin(), lst.cend(), vec.begin());

b.没有错误,但是vec还是空,reserve只是改变vec能存的最大容量,目前能存的容量没有改变

练习10.9

#include 
#include 
#include 
#include 

template  auto println(Sequence const& seq) -> std::ostream&
{
	for(auto const& elem : seq)
		std::cout << elem << " ";
	return std::cout << std::endl;
}

auto elimDups(std::vector& vs) -> std::vector&
{
	std::sort(vs.begin(),vs.end());
	println(vs);

	auto new_end = std::unique(vs.begin(),vs.end());
	println(vs);

	vs.erase(new_end,vs.end());
	return vs;
}

int main()
{
	std::vector vs {"a", "v", "a", "s", "v", "a", "a"};
	println(vs);
	println(elimDups(vs));
	return 0;
}

练习10.11

#include 
#include 
#include 
#include 
#include 
#include 

template  inline std::ostream& println(Sequence const& seq)
{
	for(auto const& elem : seq)
		std::cout << elem << " ";
	return std::cout;
}

inline bool is_shorter(std::string const& lhs,std::string const& rhs)
{
	return lhs.size() < rhs.size();
}

void elimDups(std::vector& vs)
{
	std::sort(vs.begin(),vs.end());
	auto new_end = std::unique(vs.begin(),vs.end());
	vs.erase(new_end,vs.end());
}

int main()
{
	std::vector vec {"1234", "1234", "1234", "Hi", "alan", "wang"};
	elimDups(vec);
	std::stable_sort(vec.begin(),vec.end(),is_shorter);
	std::cout << "ex 10.11 :" << std::endl;
	println(vec);
	return 0;
}
练习10.12

#include 
#include 
#include 
#include 
#include 
#include "ex7_26.h"

inline bool compareIsbn(const Sales_data& d1,const Sales_data& d2)
{
	return d1.isbn() vec {d1,d2,d3,d4,d5};

	std::sort(vec.begin(),vec.end(),compareIsbn);

	for(const auto& elem : vec)
		std::cout << elem.isbn() << " ";
	std::cout << std::endl;
	return 0;
}
练习10.13

#include 
#include 
#include 
#include 

bool predicate(const std::string& s)
{
	return s.size()>=5;
}

int main()
{
	auto vec = std::vector{"a","aaaa","aasaa","bbbbbbb","ccc"};
	auto pivot = std::partition(vec.begin(),vec.end(),predicate);
	for(auto it = vec.begin();it!=pivot;++it)
	std::cout << *it << " ";
	std::cout << std::endl;
	
	return 0;
}
练习10.14

auto add = [](int lhs,int rhs){return lhs+rhs;};
练习10.15

int a = 10;
auto add = [a](int b){return a+b;};
练习10.16

#include 
#include 
#include 
#include 

void elimDups(std::vector& vec)
{
	sort(vec.begin(),vec.end());
	auto new_end = std::unique(vec.begin(),vec.end());
	vec.erase(new_end,vec.end());
}

void biggies(std::vector vec,std::size_t sz)
{
	using std::string;
	
	elimDups(vec);
	
	std::stable_sort(vec.begin(),vec.end(),[](string const& lhs,string const& rhs){return lhs.size()=sz;});
	
	std::for_each(wc,vec.end(),[](const string& s){std::cout << s << " ";});
	std::cout << std::endl;
}

int main()
{
	std::vector vec {"1234", "1234", "1234", "hi~", "alan", "alan", "cp"};
	biggies(vec,3);
	std::cout << std::endl;
	return 0;
}

练习10.17

#include 
#include 
#include 
#include 
#include 
#include "ex7_26.h"

int main()
{
	Sales_data d1("aa"),d2("aaaa"),d3("aaa"),d4("z"),d5("aaaaz");
	std::vector vec {d1,d2,d3,d4,d5};

	std::sort(vec.begin(),vec.end(),[](const Sales_data& d1,const Sales_data& d2){return d1.isbn()

练习10.18 & 10.19

#include 
#include 
#include 
#include 

//from ex 10.9
void elimdups(std::vector& vs)
{
	std::sort(vs.begin(), vs.end());
	auto new_end = std::unique(vs.begin(), vs.end());
	vs.erase(new_end, vs.end());
}

//ex10.18
void biggies_partition(std::vector& vs, std::size_t sz)
{
	elimdups(vs);

	auto pivot = partition(vs.begin(), vs.end(), [sz](const std::string& s)
	{
		return s.size() >= sz;
	});

	for (auto it = vs.cbegin(); it != pivot; ++it)
		std::cout << *it << " ";
}

//ex10.19
void biggies_stable_partition(std::vector& vs, std::size_t sz)
{
	elimdups(vs);

	auto pivot = stable_partition(vs.begin(), vs.end(), [sz](const std::string& s)
	{
		return s.size() >= sz;
	});

	for (auto it = vs.cbegin(); it != pivot; ++it)
		std::cout << *it << " ";
}

int main()
{
	//ex10.18
	std::vector v {"the",  "quick", "red",  "fox", "jumps", "over", "the",   "slow", "red", "turtle"};

	std::cout << "ex10.18: ";
	std::vector v1(v);
	biggies_partition(v1, 4);
	std::cout << std::endl;

	//ex10.19
	std::cout << "ex10.19: ";
	std::vector v2(v);
	biggies_stable_partition(v2, 4);
	std::cout << std::endl;

	return 0;
}

练习10.20

#include 
#include 
#include 
#include 

std::size_t bigerThan6(std::vector vec)
{
	return count_if(vec.begin(),vec.end(),[](std::string const& s){return s.size()>6;});
}

int main()
{
	std::vector vec{"alan",    "moophy",  "1234567", "1234567", "1234567", "1234567"};
    std::cout << bigerThan6(vec) << std::endl;
}

练习10.21

#include 
#include 
#include 
#include 

int main()
{
	int i = 7;
	auto fun = [&i]()
	{
		return --i?false:true;
	};
	while(!fun())
		std::cout << i << " ";
	std::cout << std::endl;
}

练习10.22

#include 
#include 
#include 
#include 
#include 

using namespace std::placeholders;

bool isBigerThan6(std::string& s,std::size_t sz)
{
	return s.size()>6;
}

int main()
{
	std::vector vec {"alan", "moophy", "1234567", "1234567", "1234567", "1234567"};
	std::cout << count_if(vec.begin(),vec.end(),bind(isBigerThan6,_1,6)) << std::endl;
}

练习10.22

#include 
#include 
#include 
#include 
#include 

using namespace std::placeholders;

inline bool check_size(const std::string& s,std::string::size_type sz)
{
	return s.size()::const_iterator find_first_bigger(const std::vector& vec,const std::string& s)
{
	return find_if(vec.cbegin(),vec.cend(),bind(check_size,s,_1));
}

int main()
{
	std::vector vec{1,2,3,4,5,6,7};
	std::string s("test");
	std::cout << *find_first_bigger(vec,s) << std::endl;
	return 0;
}

练习10.25

#include 
#include 
#include 
#include 
#include 

using namespace std::placeholders;
using std::vector;
using std::string;

void elimDups(vector& vs)
{
	sort(vs.begin(),vs.end());
	vs.erase(unique(vs.begin(),vs.end()));
}

bool check_size(const string& s,string::size_type sz)
{
	return s.size()>=sz;
}

void biggies(vector& words,vector::size_type sz)
{
	elimDups(words);
	auto iter = std::stable_partition(words.begin(),words.end(),bind(check_size,_1,sz));
	for_each(words.begin(),iter,[](const string&s){std::cout< vec{"the",  "quick", "red",  "fox", "jumps", "over", "the", "slow", "red", "turtle"};
	 biggies(vec,4);
	return 0;
}

练习10.27

#include 
#include 
#include 
#include 

int main()
{
	std::vector vec{1,1,2,2,2,3,3,3,4,5};
	std::list lst;
	
	std::unique_copy(vec.begin(),vec.end(),back_inserter(lst));
	
	for(auto elem : lst)
	std::cout << elem << " ";
	std::cout << std::endl;	
} 

练习10.28

#include 
#include 
#include 
#include 

template  void print(Sequence const& seq)
{
	for(const auto& elem : seq)
	std::cout << elem << " ";
	std::cout << std::endl;
}

int main()
{
	std::vector vec{1,2,3,4,5,6,7,8,9};
	std::list lst1,lst2,lst3;
	
	std::unique_copy(vec.cbegin(),vec.cend(),inserter(lst1,lst1.begin()));
	print(lst1);
	
	std::unique_copy(vec.cbegin(),vec.cend(),back_inserter(lst2));
	print(lst2);
	
	std::unique_copy(vec.cbegin(),vec.cend(),front_inserter(lst3));
	print(lst3);
} 

练习10.29

#include 
#include 
#include 
#include 
#include 
#include 

using std::string;

int main()
{
	std::ifstream ifs("data.txt");
	std::istream_iterator in(ifs),eof;
	std::vector vec;
	std::copy(in,eof,back_inserter(vec));
	
	std::copy(vec.cbegin(),vec.cend(),std::ostream_iterator(std::cout,"\n"));
	return 0;
}

练习10.30

#include 
#include 
#include 
#include 

int main()
{
	std::istream_iterator in_iter(std::cin),eof;
	std::vector vec;
	while(in_iter!=eof)
	vec.push_back(*in_iter++);
	std::sort(vec.begin(),vec.end());
	std::copy(vec.cbegin(),vec.cend(),std::ostream_iterator(std::cout," "));
}

练习10.31

#include 
#include 
#include 
#include 

int main()
{
	std::istream_iterator in_iter(std::cin),eof;
	std::vector vec;
	while(in_iter!=eof)
	vec.push_back(*in_iter++);
	std::sort(vec.begin(),vec.end());
	std::unique_copy(vec.cbegin(),vec.cend(),std::ostream_iterator(std::cout," "));
}

练习10.32

#include 
#include 
#include 
#include 
#include 
#include "Sales_item.h"

int main()
{
    std::istream_iterator in_iter(std::cin),in_eof;
    std::vector vec;
    
    while(in_iter!=in_eof)
    vec.push_back(*in_iter++);
    sort(vec.begin(),vec.end(),[](Sales_item const& lhs,Sales_item const& rhs){return lhs.isbn()isbn();});
    	std::cout << std::accumulate(beg,end,Sales_item(beg->isbn())) << std::endl;
	}
}

练习10.33

#include 
#include 
#include 

int main(int argc, char** argv)
{
	if (argc != 4) return -1;

	std::ifstream ifs(argv[1]);
	std::ofstream ofs_odd(argv[2]), ofs_even(argv[3]);

	std::istream_iterator in(ifs), in_eof;
	std::ostream_iterator out_odd(ofs_odd, " "), out_even(ofs_even, "\n");

	std::for_each(in, in_eof, [&out_odd, &out_even](const int i)
	{
		*(i & 0x1 ? out_odd : out_even)++ = i;
	});

	return 0;
}

练习10.34~10.37

#include 
#include 
#include 
#include 
#include 
#include 


//ex 10.34
inline void r_print(const std::vector& v)
{
    std::for_each(v.crbegin(), v.crend(),
                  [](const std::string& s) { std::cout << s << " "; });
}

//! ex 10.35
inline void r_withOrdinary_print(const std::vector& v)
{
    for (auto it = std::prev(v.cend()); it != std::prev(v.cbegin()); --it)
        std::cout << *it << " ";
}

//ex 10.36
inline std::list::iterator find_last_0(std::list& l)
{
    auto r_it = std::find(l.rbegin(), l.rend(), 0);
    auto it = r_it.base();
    return std::prev(it);
}

//ex 10.37:
inline void vec2list_3_7_reverse(const std::vector& v, std::list& l)
{
    std::copy(v.crbegin() + 3, v.crbegin() + 8, std::back_inserter(l));
}

int main()
{

    std::vector v = {"aa", "bb", "cc"};

    //test for 10.34
    r_print(v);
    std::cout << "\n";

    //test for 10.35
    r_withOrdinary_print(v);
    std::cout << "\n";

    //test for 10.36
    std::list l = {1, 2, 3, 4, 0, 5, 6};
    auto it = find_last_0(l);
    std::cout << *it << "\n";

    //test for 10.37
    std::vector vi = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::list lst;
    vec2list_3_7_reverse(vi, lst);
    for (auto e : lst) std::cout << e << " ";
    std::cout << std::endl;

    return 0;
}

练习10.42

#include 
#include 
#include 

using std::string;
using std::list;

void elimDups(list& words)
{
	words.sort();
	words.unique();
}

int main()
{
	list l = {"aa", "aa", "aa", "aa", "aasss", "aa"};
	elimDups(l);
	for (const auto& e : l)
		std::cout << e << " ";
	std::cout << std::endl;
}


你可能感兴趣的:(《C++primer(第五版)》学习之路-第十章:泛型算法)