C++ primer 5th 第10章 泛型算法
=====================================================================
第10章 泛型算法 336页 算法algorithm头文件
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
vector<int> ivec = { 1,2,3,4,5,6};
int ival = 42;//我们想查找的值
//如果在vec中找到想要的元素,则返回结果指向它,否则返回结果为vec.cend()
auto res = find(ivec.begin(), ivec.end(), ival);
cout << "the value " << ival
<< (res == ivec.cend() ? " is not present" : " is present")
<< endl;
list<string> lst{ "hello ","a value ","world" };
string s = "a value ";
//此调用在list中查找元素
auto res1 = find(lst.begin(), lst.end(), s);
cout << s << " is " << (res1 == lst.cend() ? "No" : "Yes") << endl;
int ia[] = { 27,210,12,47,109,83 };
int val = 83;
int* res2= find(begin(ia), end(ia), val);
cout << *res2 << endl;
//在从ia[1]开始,直到(但不包含)的ia[4]的范围内查找元素
auto res3 = find(ia + 1, ia + 4, val);
system("pause");
return 0;
}
#ifdef DECLARATION
find的工作实在一个未排序的元素序列中寻找一个特定的元素,执行的步骤:
1. 访问序列中的首元素。
2. 比较此元素与我们要查找的元素。
3. 如果此元素与我们要查找的值匹配,find返回标识此元素的值。
4. 否则,find前进到下一个元素,重复执行步骤2和3。
5. 如果到达序列末尾,find应停止。
6. 如果find到达序列末尾,他应该返回一个指出元素未找到的值。此值和步骤3
返回的值必须具有相容的类型。
#endif
=====================================================================
第10章 泛型算法 337页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
/*练习10.1:头文件algorithm中定义了一个名为count的函数,它类似find,接受
一对迭代器和一个值作为参数。count返回给定值在序列中出现的次数。编写程序,读
取int序列存入vector中,打印有多少个元素的值等于给定值。*/
vector<int> ivec = { 1,2,3,4,5,6,1,2,3,4,5,3,2 };
int ival = count(ivec.begin(), ivec.end(), 2);//统计2出现的次数,返回该值并传给ival
cout << ival << endl;//输出内容:3
/*练习10.2:重做上一题,但读取string序列存入 list 中。*/
list<string> slst = { "abc","def","abc" };
string s = "abc";
int value = count(slst.begin(), slst.end(), s);//查找"abc"出现的次数
cout << value << endl;//输出内容:2
system("pause");
return 0;
}
=====================================================================
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
bool SearchVal(vector<int>& v, int val)
{
if (find(v.begin(), v.end(), val) != v.end())//如果结果不等v1.end表示找到,
{
int cnt = count(v.begin(), v.end(), val);//val出现的次数
cout << cnt << endl;
return true;
}
else
cout << "未找到 " << val << endl;
return false;
}
int main()
{
vector<int> v1 = { 7,1,2,3,4,5,6,7,1,3,5,7 };
int val = 100;
SearchVal(v1, val);//查找100出现的次数
SearchVal(v1, 7);//查找7出现次数
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 338页 只读算法
=====================================================================
//QQ108201645编写
#include <numeric>//numeric译:数
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
/*
只读算法
一些算法只会读取其输入范围内的元素,而不会改变这些值,find就是其中的一种算法,
在10.1节练习(第337页)中使用的count函数也是如此。
另一个只读算法是accumulate,它包含在头文件<numeric>中,accumulate函数
接受三个参数:前两个表示了需要求和的元素的范围,第三个表示和的初值。
accumulate的第三个值决定了函数中使用哪个加法运算符以及返回值类型。
而且,accumulate有一个编程假定:将范围里的元素加到第三个参数上的操作是可行的,这些元素类型必须和第三个参数的类型匹配,或者能转换为第三个参数值的类型。
*/
vector<int> ivec{11, 22, 33, 44, 55, 66, 77, 88, 99};
int sum = accumulate(ivec.begin(), ivec.end(), 0);//从ivec.begin开始,到end结束,初值是0
cout << sum << endl;//输出495
vector<string> svec{ "hello ","world ","How ","you ","doing " };
string s = accumulate(svec.begin(), svec.end(), string(""));//把vector的元素连接起来
//错误:因为传递的是字符串值,const char*上没有定义+运算符
//string s = accumulate(svec.cbegin(), svec.cend(), "");//开始连接字符串
cout << s << endl; //输出hello world How you doing
/*只读算法equal,用于比较两个序列是否保存相同的值。它将第一个序列中
的每个元素与第二个序列中的对应元素进行比较。如果对应元素都相等,则返回
true,否则返回false。算法接受三个迭代器:前两个(与以往一样)表示第一个序
列中的元素范围,第三个表示第二个序列的首元素*/
vector<string> svec1(svec);
//svec1与svec中的元素数目应该相同才能比较
bool result = equal(svec.cbegin(), svec.cend(), svec1.cbegin());
cout << result << endl;//输出1
vector<int> v1{ 1, 2, 3, 4, 5 };
vector<int> v2{ 1, 2, 3, 4, 6 };
cout << (equal(v1.cbegin(), v1.cend(), v2.cbegin()) == true ? "euqal" : "not euqal") << endl;
//输出not euqal
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 338页 练习题
=====================================================================
//QQ108201645编写
#include<vector>
#include<algorithm>
#include<numeric>
#include<iostream>
#pragma warning(disable:4996)
using namespace std;
int main()
{
/*练习10.3:用accumulate求一个vector<int>中的元素之和。*/
vector<int> v1 = { 1,2,3,4,5,6,7 };
int val = accumulate(v1.begin(), v1.end(), 0);//所在头文件numeric
cout << val << endl;//输出28
/*练习10.4:假定v是一个vector<double>,那么调用 accumulate(v.cbegin(),
v.cend(), 0) 有何错误(如果存在的话)?
由于类型不同,隐式转换时会导致丢失精度,要把0.0作为第三个参数传递给accumulate。
*/
/*练习10.5:在本节对名册(roster)调用equal 的例子中,如果两个名册中保存的都是
C风格字符串而不是string,会发生什么?*/
const char *p[] = { "Hello","World","!" };
const char *q[] = { strdup(p[0]),strdup(p[1]),strdup(p[2]) };//把p里的元素分别复制到*q[]
const char *r[] = { p[0],p[1],p[2] };
cout << equal(begin(p), end(p), q) << endl;//内容相同,但元素地址不同,输出 0
cout << equal(begin(p), end(p), r) << endl;//p指针的拷贝,指向相同地址,输出 1
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 340页 写容器的算法
=====================================================================
//QQ108201645编写
#include <vector>
#include <iostream>
using namespace std;
typedef vector<int> INTVEC;
void ShowVec(INTVEC& v)
{
for (int i : v)
{
cout << i << " ";
}
cout << endl;
}
int main()
{
INTVEC vec{ 1,2,3,4,5,6,7,9 };
ShowVec(vec);//输出内容1 2 3 4 5 6 7 9
fill(vec.begin(), vec.end(), 0);//接受一对迭代器表示一个范围,fill将给给这个值并赋值给范围内的每个元素
ShowVec(vec); //输出内容0 0 0 0 0 0 0 0
fill(vec.begin(), vec.begin() + vec.size() / 2, 10);//把迭代器begin到end()的一半的元素每个都写入10
ShowVec(vec);//输出内容 10 10 10 10 0 0 0 0
//接受一个迭代器指定首位置,一个计数器指定写入个数,还有一个值
fill_n(vec.begin(), vec.size(), 0);//把0写入到从begin开始的位置,每写入一次后,迭代器自增,写入次数为vec.size(),
ShowVec(vec);//输出内容0 0 0 0 0 0 0 0
fill_n(vec.begin()+5, 3, 1);//从begin()偏移5的位置开始写入单个字符,每写入一个后,迭代器自增,大小3个字符
ShowVec(vec);//输出内容0 0 0 0 0 1 1 1
cout << "大小: " << vec.size() << endl;//输出内容 大小: 8
//fill_n(vec.begin(), 10, 0);//错误,修改从begin开始的10个元素,但根本没有10个,越界
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 340页 介绍back_insert
=====================================================================
//QQ108201645编写
#include <vector>
#include <iostream>
using namespace std;
typedef vector<int> INTVEC;
void ShowVec(INTVEC& v)
{
cout << "大小: " << v.size() << endl;
for (int i : v)
{
cout << i << " ";
}
cout << endl;
}
int main()
{
INTVEC vec;
auto it = back_inserter(vec);//通过它赋值会将元素添加到vec中
*it++ = 42;//vec中现在有一个元素,值为42
*it = 43;//vec中现在有一个元素,值为43
ShowVec(vec);
//正确:back_insert创建一个插入迭代器,可用来向vec加元素
fill_n(back_inserter(vec), 10, 0);//添加10个元素到vec
ShowVec(vec);
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 341页 拷贝算法
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
void NewVecShow(vector<int> v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
void ShowList(list<int>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
void ShowVec(vector<int>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
int a1[] = { 0,1,2,3,4,5,6,7,8,9 };
//int每个占4个字节,所以前面是10个数组乘4就是:40/4=10
int a2[sizeof(a1) / sizeof(*a1)];//a2大小与a1一样
//ret指向拷贝到a2的尾元素之后的位置
auto ret = copy(begin(a1), end(a1), a2);//把a1的内容拷贝给a2
/*int* beg = a2, *end = a2 + sizeof(a1) / sizeof(*a1);*/
NewVecShow({ begin(a2), end(a2) });//迭代器方式初始化vector
//输出a2内容:0 1 2 3 4 5 6 7 8 9
list<int> ilst = { 0,1,2,3,4,5,6,7,8,9 ,0 };//创建一个链表对象并初始化
ShowList(ilst);//输出list内容:0 1 2 3 4 5 6 7 8 9 0
//replace在算法头文件
replace(ilst.begin(),ilst.end(), 0, 42);//把list从begin开始到end结束的全部数值为0元素都改为42
ShowList(ilst);//输出list内容:42 1 2 3 4 5 6 7 8 9 42
vector<int> ivec{ 42,10,11,12,13,14,15 };
/*前两个是迭代器,表示输入序列,后两个一个是要搜索的值,
另一个是新值。它将所有等于第一个值的元素替换成第二个值*/
replace_copy(ilst.cbegin(), ilst.cend(),
back_inserter(ivec), 42, 43);//把list的内容复制到ivec的尾部,如果原来list中值为42的元素,在vector中就改为43
ShowList(ilst);//输出list内容: 42 1 2 3 4 5 6 7 8 9 42
ShowVec(ivec);//输出Vec内容: 42 10 11 12 13 14 15 43 1 2 3 4 5 6 7 8 9 43
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 342页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
void ShowVec(vector<int>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
/*练习10.6:编写程序,使用fill_n将一个序列中的 int 值都设置为 0。*/
vector<int> ivec{ 42,10,11,12,13,14,15 };
fill(ivec.begin(), ivec.begin() + ivec.size() / 2, 1);
ShowVec(ivec);//输出Vec内容:1 1 1 12 13 14 15
fill_n(ivec.begin(), ivec.size(), 0);
ShowVec(ivec);//输出Vec内容:0 0 0 0 0 0 0
/*练习10.7:下面程序是否有错误?如果有,请改正:
(a) vector<int> vec; list<int> lst; int i;
while (cin >> i)
lst.push_back(i);
copy(lst.cbegin(), lst.cend(), vec.begin());
(b)vector<int> vec;
vec.reserve(10);//分配能容纳10个元素的内存空间
fill_n(vec.begin(), 10, 0);
*/
/*
(a)是错误的。因为泛型算法的一个基本特点是:通过迭代器操作容器,
因此不能直接向/从容器添加、删除元素,无法改变容器的大小。因此,对于copy
算法,要求目标序列至少要包含与源序列一样多的元素,因此程序中,vec进行缺省
初始化,它是空的,copy无法进行,如要改变容器大小,需要使用一类特殊的称为
插入器的迭代器。我们可以将第三个参数改为back_inserter(vec),通过它,
copy算法即可将lst中元素的拷贝插入到vec的末尾。*/
list<int> lst{ 1,2,3 };
vector<int> vec;//输出内容1
copy(lst.begin(), lst.end(), back_inserter(vec));
cout << equal(lst.begin(), lst.end(), vec.begin()) << endl;
ShowVec(vec);//输出内容1 2 3
cout << vec.size() <<" "<<vec.capacity()<< endl;
//fill_n(vec.back(), vec.size(), 0);把每个元素都改成0,报错
fill(vec.begin(), vec.end(), 10);//把每个元素都改成10
//测试原先元素的vector
vector<int> ivec1, ivec2{ 1,2,3 };
//fill_n(ivec1.begin(), 10, 0);//没有元素报错
fill_n(back_inserter(ivec1), 10, 1);//正确,返回一个迭代器元素并添加数值为1
//fill_n(ivec2.begin(), 10, 0);//报错.没有多余的7个元素提供改写元素
fill_n(back_inserter(vec), 10, 0);
/*练习10.8:本节提到过,标准库算法不会改变它们所操作的容器的大小。为什么使用
back_inserter不会使这一断言失效?*/
/*back_inserter不属于标准库泛型算法,它是在头文件iterator中定义的,
而泛型算法是在algorithm中定义的。
标准库算法不直接操作容器,只操作迭代器,从而间接访问容器,能不能删除不在于算法,而在
于传递给它们的迭代器是否有这样的能力*/
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 343页 重排容器元素的算法
=====================================================================
the quick red fox jumps over the slow red turtle
fox | jumps | over | quick | red | slow | the | turtle |
消除重复单词
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
void elimDups(vector<string>& words)
{
//按字典序排序words,以便查找重复单词
sort(words.begin(), words.end());//进行排序
//unique重排输入范围,使得每个单词只出现一次
//排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//unique并不删除任何元素,只是覆盖重复的相邻元素
//使用向量操作erase删除重复单词(删除重复元素),返回的迭代器指向最后一个不重复元素之后的位置
//使用erase删除从end_unique开始直到words末尾的范围内的所有元素。即使没有重复单词,这样的调用erase也是安全的
words.erase(end_unique, words.end());
}
void ShowVec(vector<string>& v)
{
cout << "size = " << v.size() << endl;
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
istringstream InitIs;
InitIs.str("the quick red fox jumps over the slow red turtle");//把字符串传给InitIs
vector<string> svec;
string s;
while (!InitIs.eof())
{
InitIs >> s;
svec.push_back(s);
}
ShowVec(svec);//输出内容: size = 10 the quick red fox jumps over the slow red turtle
elimDups(svec);
ShowVec(svec);//输出内容: size = 8 fox jumps over quick red slow the turtle
system("pause");
return 0;
}
=====================================================================
fox | jumps | over | quick | red | red | slow | the | the | turtle |
注意,单词red和the各出现了两次
使用unique,vector将变成
fox | jumps | over | quick | red | slow | the | turtle | ??? | ??? |
最后一个不重复元素之后的位置就是end_unique
=====================================================================
第10章 泛型算法 344页 练习题
=====================================================================
//QQ108201645编写
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
/*练习10.9:实现你自己的elimDups。测试你的程序,分别在读取输入后、调用 unique
后以及调用erase后打印vector的内容。*/
void elimDups(vector<int>& v)
{
sort(v.begin(), v.end());//如果不排序则无法删除不是间隔的555
/*auto*/ vector<int>::const_iterator pos = unique(v.begin(), v.end());
cout << typeid(pos).name() << endl;
v.erase(pos, v.end());
}
void Show(vector<int> &v)
{
cout << v.size() << endl;
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
vector<int> ivec{ 111,111,222,333,444,444,555,666,777,888,999,555 };
cout << ivec.size() << endl;
elimDups(ivec);
Show(ivec);
vector<int> ivec1;
replace_copy(ivec.begin(), ivec.end(), back_inserter(ivec1), 0, 42);
Show(ivec1);
cout << equal(ivec.begin(), ivec.end(), ivec1.begin()) << endl;
/*练习10.10:你认为算法不改变容器大小的原因是什么?
算法与容器分离,算法不改变容器将使用户不需要顾忌容器的迭代器失效问题。*/
system("pause");
return 0;
}
=====================================================================
//删除vector电话号码排序及删除重复元素
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
void Show(vector<string> &v)
{
cout << "------------" << endl;
for (auto i : v)
{
cout << i << endl;
}
cout << "------------" << endl;
}
int main()
{
vector<string> svec = { "18600001112","18244443333","18600011111",
"13800001111","13800001112","15611112222","15611112223","15611112224","13800001111" };
Show(svec);
cout << "排序后" << endl;
sort(svec.begin(), svec.end());//排序
string s = "13800001111";
svec.erase(unique(svec.begin(), svec.end()), svec.end());//删除重复的"13800001111"
Show(svec);
cout << "删除13800001111" << endl;
svec.erase(remove(svec.begin(), svec.end(), s), svec.end());//删除vector内内容为"13800001111"的元素
Show(svec);
system("pause");
return 0;
}
/*
输出内容
------------
18600001112
18244443333
18600011111
13800001111
13800001112
15611112222
15611112223
15611112224
13800001111
------------
排序后
------------
13800001111
13800001112
15611112222
15611112223
15611112224
18244443333
18600001112
18600011111
------------
删除13800001111
------------
13800001112
15611112222
15611112223
15611112224
18244443333
18600001112
18600011111
------------
请按任意键继续. . .
*/
=====================================================================
第10章 泛型算法 344页 向算法传递函数(排序)
=====================================================================
//QQ108201645编写
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<sstream>
using namespace std;
void Show(vector<string> &v)
{
cout << "------------" << endl;
for (auto i : v)
{
cout << i << " ";
}
cout << "\n------------" << endl;
}
bool isShorter(const string& s1, const string& s2)
{
return s1.size() < s2.size();
}
void elimDups(vector<string>& words)
{
//按字典序排序words,以便查找重复单词
sort(words.begin(), words.end());//进行排序
//unique重排输入范围,使得每个单词只出现一次
//排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//unique并不删除任何元素,只是覆盖重复的相邻元素
//使用向量操作erase删除重复单词(删除重复元素),返回的迭代器指向最后一个不重复元素之后的位置
//使用erase删除从end_unique开始直到words末尾的范围内的所有元素。即使没有重复单词,这样的调用erase也是安全的
words.erase(end_unique, words.end());
}
#ifdef DECLARATION
C++中sort和stable_sort的区别:
1.sort是快速排序实现,因此是不稳定的;stable_sort是归并排序实现,因此是稳定的;
2.对于相等的元素sort可能改变顺序,stable_sort保证排序后相等的元素次序不变;
3.如果提供了比较函数,sort不要求比较函数的参数被限定为const,而stable_sort则要求参数被限定为const,否则编译不能通过。
#endif
int main()
{
istringstream InitIs;
InitIs.str("the quick red fox jumps over the slow red turtle");//把字符串传给InitIs
vector<string> svec;
string s;
while (!InitIs.eof())
{
InitIs >> s;
svec.push_back(s);
}
cout << "输出内容" << endl;
Show(svec);
cout << "字典序,并消除重复单词" << endl;
elimDups(svec);
Show(svec);
cout << "按短至长排序" << endl;
sort(svec.begin(), svec.end(), isShorter);
Show(svec);
cout << "按字典重排,并消除重复单词" << endl;
elimDups(svec);//按字典重排,并消除重复单词
cout << "按长度重新排序,长度相同的单词维持字典序" << endl;
stable_sort(svec.begin(), svec.end(), isShorter);
Show(svec);
cout << "按字典重排" << endl;
stable_sort(svec.begin(), svec.end());
Show(svec);
system("pause");
return 0;
}
/*
输出内容
------------
the quick red fox jumps over the slow red turtle
------------
字典序,并消除重复单词
------------
fox jumps over quick red slow the turtle
------------
按短至长排序
------------
fox red the over slow jumps quick turtle
------------
按字典重排,并消除重复单词
按长度重新排序,长度相同的单词维持字典序
------------
fox red the over slow jumps quick turtle
------------
按字典重排
------------
fox jumps over quick red slow the turtle
------------
请按任意键继续. . .
*/
=====================================================================
第10章 泛型算法 345页 练习题
=====================================================================
//QQ108201645编写
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<sstream>
using namespace std;
void Show(vector<string>& v)
{
for (auto c : v)
cout << c << " ";
cout << endl;
}
void elimDups(vector<string>& v)
{
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
}
bool isShorter(const string& iv, const string& iv1)
{
return iv.size() < iv1.size();
}
int main()
{
/*练习10.11:编写程序,使用stable_sort和isShorter将传递给你的elimDups
版本的vector排序。打印vector的内容,验证你的程序的正确性。*/
vector<string> ivec{ "111","2222","333","444","5555",
"6666","777","888","apple","111000","111","2222","333","444","5555" };
//elimDups(ivec);
Show(ivec);
stable_sort(ivec.begin(), ivec.end(), isShorter);
Show(ivec);
sort(ivec.begin(), ivec.end(), isShorter);
Show(ivec);
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
//保存为Sales_data.h头文件
#ifndef _SALES_DATA_H_
#define _SALES_DATA_H_
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
/*定义在public:说明符之后的成员在整个程序内可被访问public成员定义类的
接口*/
/*定义在private:说明符之后成员只被类的函数访问,但不能被使用
该类的代码访问,private封装了(即隐藏了)类的实现细节*/
//使用class而非struct开始类的定义,只是形式不同,唯一区别就是默认访问权限不同
//没有定义public: protected: private: 的情况下.在struct里都是public
class Sales_data
{
public://公有成员
//新增构造函数(不同的类内初始化方式)
Sales_data() = default;//默认构造函数可以声明在类类部,也可以作为定义出现在类的外部
explicit Sales_data(const std::string &s, unsigned n, double p) :
bookNo(s), units_sold(n), revenue(p*n) {}
/*Sales_data(std::istream& is)
{
read(is, *this);
}*/
//保留默认构造函数
explicit Sales_data(std::string s)
:bookNo(s) {}//bookNo(s)表示构造函数列表初始化(构造函数初始值列表)
//只允许出现在类内声明构造函数时使用explicit
explicit Sales_data(std::istream& is)
{
read(is, *this);
}
friend Sales_data add(const Sales_data&, const Sales_data&);
friend std::istream& read(std::istream&, Sales_data&);
friend std::ostream& print(std::ostream&, const Sales_data&);
friend ifstream& read(ifstream& in, Sales_data& item)
{
double price = 0;
in >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return in;
}
friend ofstream& print(ofstream& out, const Sales_data& item)
{
out << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return out;
}
friend std::istream& operator>>(std::istream& is, Sales_data&);//operator>>重载,支持cin>>对象名接收
friend std::ostream& operator<<(std::ostream& os, const Sales_data&);//operator<<重载,支持cin>>对象名直接输出内容
//之前已有的其它成员
std::string isbn() const;
Sales_data& combine(const Sales_data&);
private://私有成员
double ave_price()const;
std::string bookNo;
unsigned units_sold = 0;//c++11开始支持类体内初始化(变量名译:单独售出)
double revenue = 0.0;//初始化revenue(译:财政收入)
};//这里要加分号
Sales_data add(const Sales_data &lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;//把lhs的数据拷贝给sum
sum.combine(rhs);//把rhs的数据成员加到sum当中
return sum;
}
//定义read和print函数
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
cout << "输入书的编号、售出数量、单价" << endl;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return os;
}
//上面两个等同于operator>>与operator<<重载
std::istream& operator>>(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& operator<<(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price();
return os;
}
std::string Sales_data::isbn() const
{
//return bookNo;//用于返回Sales_data的数据成员
return this->bookNo;//同上
//默认情况this指针指向非常量的常量指针
}
//函数combine设计初衷类型复合赋值运算符+=
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;//把rhs的成员加到this对象的成员上
revenue += rhs.revenue;
return *this;//返回调用该函数的对象
}
double Sales_data::ave_price()const
{
return units_sold ? revenue / units_sold : 0;
}
#endif
―――――――――――――――――――――――――――――――――――――――
//QQ108201645编写
#include<iostream>
#include<algorithm>
#include<vector>
#include "Sales_data.h"
using namespace std;
/*练习10.12:遍写名为compareIsbn的函数,比较两个 Sales_data 对象的isbn()
成员。使用这个函数排序一个保存 Sales_data 对象的 vector。*/
bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.isbn() < rhs.isbn();
}
void Show(vector<Sales_data>& v)
{
for (auto i : v)
{
cout << i << endl;
}
cout << endl;
}
int main()
{
vector<Sales_data> sdata;
Sales_data sd;
while (read(cin,sd))
{
sdata.push_back(sd);
}
stable_sort(sdata.begin(), sdata.end(), compareIsbn);
Show(sdata);
system("pause");
return 0;
}
/*
输出:
输入书的编号、售出数量、单价
12-45 5 20
输入书的编号、售出数量、单价
12-45 5 20
输入书的编号、售出数量、单价
12-46 5 20
输入书的编号、售出数量、单价
12-45 6 23
输入书的编号、售出数量、单价
12-46 7 55
输入书的编号、售出数量、单价
^Z
12-45 5 100 20
12-45 5 100 20
12-45 6 138 23
12-46 5 100 20
12-46 7 385 55
*/
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
inline void output_words(vector<string>::iterator beg, vector<string>::iterator end)
{
while (beg!=end)
{
cout << *beg++ << " ";
}
cout << endl;
}
bool five_or_more(const string& s1)
{
return s1.size() >= 5;//判断元素中的长度是否大等于5,如果是的话就排到前面
}
int main()
{
string s;
vector<string> words;
while (cin >> s)
{
words.push_back(s);
}
output_words(words.begin(), words.end());
auto iter = partition(words.begin(), words.end(), five_or_more);//结果为true时排在容器的前面
cout << "经由partition处理后" << endl;
output_words(words.begin(), words.end());
cout << "---------" << endl;
system("pause");
return 0;
}
/*
控制台内容
abc def hij 1234a 45678b abcde
^Z
abc def hij 1234a 45678b abcde
经由partition处理后
abcde 45678b 1234a hij def abc
---------
请按任意键继续. . .
*/
=====================================================================
//QQ108201645编写
#include<iostream>
#include<algorithm>
using namespace std;
void Show(int *beg, int *end)
{
while (beg != end)
{
cout << *beg++ << " ";
}
cout << endl;
}
bool Intcmp(const int& val)
{
return val <5;
}
int main()
{
int ia[] = { 1,2,6,7,5,4,3 };
partition(begin(ia), end(ia), Intcmp);//使小于5的数排在前面
Show(begin(ia), end(ia));
system("pause");
return 0;
}
/*
1 2 3 4 5 7 6
*/
=====================================================================
//QQ108201645编写
//电话号码(根据名字或号码)排序、删除重复的号码
#include<iostream>
#include<string>
#include<vector>
#include<sstream>
#include<algorithm>
using namespace std;
const string s = "大黄 15600100002 张三 13805000001 李四 15808002111 林五 15808002111 黄六 15600100002 陈七 13805000002 王八 17624005200 ";
struct Tel
{
string name_;
string number_;
Tel(const string & name, const string & number)
:name_(name), number_(number) {}
Tel() = default;
friend ostream & operator<<(ostream & os, const Tel & T)
{
os << T.name_ << " " << T.number_;
return os;
}
bool operator<(const Tel& T1)
{
return number_ < T1.number_;
}
bool operator==(const Tel& T1)
{
return number_ == T1.number_;
}
};
void Show(vector < Tel > &v)
{
cout << "..............." << endl;
for (auto i : v)
cout << i << endl;
cout << "..............." << endl;
}
bool isName(const struct Tel& t1, const struct Tel& t2)
{
return t1.name_ < t2.name_;
}
bool isNumber(const struct Tel& t1, const struct Tel& t2)
{
return t1.number_ < t2.number_;
}
int main()
{
vector < Tel > tvec;
istringstream is;
is.str(s);
string name, number;
while (!is.eof())
{
is >> name >> number;
tvec.emplace_back(name, number);
}
Show(tvec);
cout << "根据姓名排序" << endl;
stable_sort(tvec.begin(), tvec.end(), isName);
Show(tvec);
cout << "根据号码排序" << endl;
stable_sort(tvec.begin(), tvec.end(), isNumber);
Show(tvec);
cout << "删除重复电话号码" << endl;
vector<Tel>::iterator end_unique = unique(tvec.begin(), tvec.end());
tvec.erase(end_unique, tvec.end());//删除重复内容
Show(tvec);
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 345页 lambda表达式
=====================================================================
/* 一个lambda表达式表示一个可调用的代码单元。我们可以理解成一个未命名的
内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表和一个函数
体。但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式
[capture list](parameter list) -> return type { function body } */
=====================================================================
//QQ108201645编写
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
void ShowVec(vector<string>::iterator beg,//范围输出
vector<string>::iterator end, string::size_type sz);//函数声明
void ShowVec(vector<string> &v);//函数声明
//如果ctr的值大于1,返回word的复数形式(201页内容)
string make_plural(size_t ctr, const string &word,
const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
void elimDups(vector<string>& words)
{
//按字典序排序words,以便查找重复单词
sort(words.begin(), words.end());//进行排序
//unique重排输入范围,使得每个单词只出现一次
//排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//unique并不删除任何元素,只是覆盖重复的相邻元素
//使用向量操作erase删除重复单词(删除重复元素),返回的迭代器指向最后一个不重复元素之后的位置
//使用erase删除从end_unique开始直到words末尾的范围内的所有元素。即使没有重复单词,这样的调用erase也是安全的
words.erase(end_unique, words.end());
}
bool isShorter(const string& s1, const string& s2)
{
return s1.size() < s2.size();
}
string::size_type check_size(const string& s, string::size_type sz)
{
return s.size() >= sz;
}
void biggies(vector<string> &words,
vector<string>::size_type sz)
{
elimDups(words);//将words按字典序排序,删除重复单词
//按长度排序,长度相同的单词维持字典序
ShowVec(words);
#ifdef DECLARATION
stable_sort(words.begin(), words.end(), isShorter);
#endif
//使用下面这条替换上面这条代码,功能相同
stable_sort(words.begin(), words.end(),
[](const string& s1, const string& s2)//下标:捕获列表是空的话,表明此lambda不使用它所在函数中任何局部变量
{ return s1.size() < s2.size(); });
//获取一个迭代器,指向第一个满足size()>=sz的元素
//计算满足size >=sz的元素的数目
#ifdef DECLARATION
auto it = find_if(words.begin(), words.end(),
[sz](const string& s) { return s.size() >= sz; });//捕获下标sz就可以在函数体中使用s.size() >= sz
#endif
//上面这句也可以用这句替换
//find_if的调用返回一个迭代器,指向第一个长度不小于给定参数sz的元素
//如果元素不存在,则返回words.end()的一个拷贝
auto it = find_if(words.begin(), words.end(),
bind(check_size, std::placeholders::_1, sz));//bind所在头文件functional
//bind表示绑定check_size函数的第一个参数const string& s,是第二个参数是sz
//计算满足size >= sz的元素的数目
auto count = words.end() - it;
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
#ifdef DECLARATION
ShowVec(it, words.end(), sz);
#endif
//打印长度大于等于给定词的单词,每个单词后面接一个空格
for_each(it, words.end(),//从it迭代器开始到end结束
[](const string& s) { cout << s << " "; });//s是自己的参数
cout << endl;
}
void ShowVec(vector<string>::iterator beg,
vector<string>::iterator end, string::size_type sz)//范围打印
{
cout << "打印长度大等于" << sz << "的字符串" << endl;
while (beg != end)
{
cout << *beg++ << " ";
}
cout << endl;
}
void ShowVec(vector<string> &v)//全部打印
{
cout << "全部打印" << endl;
for (auto c : v)
cout << c << " ";
cout << endl;
}
int main()
{
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
ShowVec(svec);
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
//数组排序输出
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int ia[] = { 300,5, 8 ,35,44,57,68,1,23,47,68 };
stable_sort(begin(ia), end(ia),
[](const int val,const int val1){ return val < val1; });//从小到大排序
for_each(begin(ia), end(ia),
[](const int val) {cout << val << " "; });//输出内容
cout << "\nMin = " << ia[0] << "\t Max = " << ia[sizeof(ia) / sizeof(int) - 1] << endl;
system("pause");
return 0;
}
=====================================================================
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
void Show(vector<string>& v)
{
for_each(v.begin(), v.end(),
[](const string& s){ cout << s << " "; });
cout << endl;
}
int main()
{
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
Show(svec);
size_t sz = 4;
partition(svec.begin(), svec.end(), [sz](const string& s1)
{return s1.size() <= sz; });
Show(svec);
stable_sort(svec.begin(), svec.end(), [](const string& s1,
const string& s2){return s1.size() <s2.size(); });
Show(svec);
string s = accumulate(svec.begin(), svec.end(),string(""));//连接元素的内容拷贝给s
cout << s << endl;
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 349页 练习题
=====================================================================
//QQ108201645编写
#include<iostream>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;
//如果ctr的值大于1,返回word的复数形式(201页内容)
string make_plural(size_t ctr, const string &word,
const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
void Show(vector<string>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
/*练习10.14:编写一个 lambda ,接受两个int,返回它们的和。*/
auto f = [](int i, int j) {return i + j; };
int a = f(3, 4);
cout << a << endl;//输出7
/*练习10.15:编写一个 lambda ,捕获它所在函数的 int,并接受一个 int参数。lambda
应该返回捕获的 int 和 int 参数的和。*/
auto sum = [a](int b) {return a + b; };
cout << sum(1) << endl;
/*练习10.16:使用 lambda 编写你自己版本的 biggies。*/
void biggies(vector<string>& words, vector<string>::size_type sz);//函数声明
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
Show(svec);
system("pause");
return 0;
}
void biggies(vector<string>& words, vector<string>::size_type sz)
{
sort(words.begin(), words.end());//排序
words.erase(unique(words.begin(), words.end()), words.end());//删除重复内容
stable_sort(words.begin(), words.end(), [](const string& s1,
const string& s2) {return s1.size() < s2.size(); });
//获取一个迭代器,指向第一个满足size()>=sz的元素
auto it = find_if(words.begin(), words.end(), [sz](const string& s) {return s.size() >= sz; });
auto count = words.end() - it;
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(it, words.end(),
[](const string& s) {cout << s << " "; });
cout << endl;
}
=====================================================================
//QQ108201645编写
//保存为Sales_data.h头文件
#ifndef _SALES_DATA_H_
#define _SALES_DATA_H_
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
/*定义在public:说明符之后的成员在整个程序内可被访问public成员定义类的
接口*/
/*定义在private:说明符之后成员只被类的函数访问,但不能被使用
该类的代码访问,private封装了(即隐藏了)类的实现细节*/
//使用class而非struct开始类的定义,只是形式不同,唯一区别就是默认访问权限不同
//没有定义public: protected: private: 的情况下.在struct里都是public
class Sales_data
{
public://公有成员
//新增构造函数(不同的类内初始化方式)
Sales_data() = default;//默认构造函数可以声明在类类部,也可以作为定义出现在类的外部
explicit Sales_data(const std::string &s, unsigned n, double p) :
bookNo(s), units_sold(n), revenue(p*n) {}
/*Sales_data(std::istream& is)
{
read(is, *this);
}*/
//保留默认构造函数
explicit Sales_data(std::string s)
:bookNo(s) {}//bookNo(s)表示构造函数列表初始化(构造函数初始值列表)
//只允许出现在类内声明构造函数时使用explicit
explicit Sales_data(std::istream& is)
{
read(is, *this);
}
friend Sales_data add(const Sales_data&, const Sales_data&);
friend std::istream& read(std::istream&, Sales_data&);
friend std::ostream& print(std::ostream&, const Sales_data&);
friend ifstream& read(ifstream& in, Sales_data& item)
{
double price = 0;
in >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return in;
}
friend ofstream& print(ofstream& out, const Sales_data& item)
{
out << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return out;
}
friend std::istream& operator>>(std::istream& is, Sales_data&);//operator>>重载,支持cin>>对象名接收
friend std::ostream& operator<<(std::ostream& os, const Sales_data&);//operator<<重载,支持cin>>对象名直接输出内容
//之前已有的其它成员
std::string isbn() const;
Sales_data& combine(const Sales_data&);
private://私有成员
double ave_price()const;
std::string bookNo;
unsigned units_sold = 0;//c++11开始支持类体内初始化(变量名译:单独售出)
double revenue = 0.0;//初始化revenue(译:财政收入)
};//这里要加分号
Sales_data add(const Sales_data &lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;//把lhs的数据拷贝给sum
sum.combine(rhs);//把rhs的数据成员加到sum当中
return sum;
}
//定义read和print函数
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
cout << "输入书的编号、售出数量、单价" << endl;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return os;
}
//上面两个等同于operator>>与operator<<重载
std::istream& operator>>(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& operator<<(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price();
return os;
}
std::string Sales_data::isbn() const
{
//return bookNo;//用于返回Sales_data的数据成员
return this->bookNo;//同上
//默认情况this指针指向非常量的常量指针
}
//函数combine设计初衷类型复合赋值运算符+=
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;//把rhs的成员加到this对象的成员上
revenue += rhs.revenue;
return *this;//返回调用该函数的对象
}
double Sales_data::ave_price()const
{
return units_sold ? revenue / units_sold : 0;
}
#endif
―――――――――――――――――――――――――――――――――――――――
//QQ108201645编写
#include<iostream>
#include <vector>
#include<algorithm>
#include "Sales_data.h"
using namespace std;
int main()
{
/*练习10.17:重写10.3.1节练习10.12(第345页)的程序,在对sort的调用中使用 lambda
来代替函数 compareIsbn。*/
Sales_data data;
vector<Sales_data> trans;
while (read(cin, data))
trans.push_back(data);
sort(trans.begin(), trans.end(), [](const Sales_data& lhs,
const Sales_data& rhs) {return lhs.isbn() < rhs.isbn(); });
for_each(trans.begin(), trans.end(), [](const Sales_data& lhs)
{cout << lhs << endl; });
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include<iostream>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;
//如果ctr的值大于1,返回word的复数形式(201页内容)
string make_plural(size_t ctr, const string &word,
const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
void Show(vector<string>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
/*练习10.18:重写 biggies,用 partition 代替 find_if。我们在10.3.1节练习10.13
(第345页)中介绍了 partition 算法。*/
void biggies(vector<string>& words, vector<string>::size_type sz);//函数声明
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
Show(svec);
system("pause");
return 0;
}
void biggies(vector<string>& words, vector<string>::size_type sz)
{
sort(words.begin(), words.end());//排序
words.erase(unique(words.begin(), words.end()), words.end());//删除重复内容
stable_sort(words.begin(), words.end(), [](const string& s1,
const string& s2) {return s1.size() < s2.size(); });
//获取一个迭代器,指向第一个满足size()>=sz的元素
/*
auto it = find_if(words.begin(), words.end(), [sz](const string& s) {return s.size() >= sz; });
auto count = words.end() - it;
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(it, words.end(),
[](const string& s) {cout << s << " "; });
cout << endl;
*/
auto it = partition(words.begin(), words.end(), [sz](const string& s) {return s.size() >= sz; });
//partition返回最后一个为true的元素之后的位置
auto count = it-words.begin();
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(words.begin(),it,
[](const string& s) {cout << s << " "; });
cout << endl;
}
=====================================================================
#include<iostream>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;
//如果ctr的值大于1,返回word的复数形式(201页内容)
string make_plural(size_t ctr, const string &word,
const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
void Show(vector<string>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
int main()
{
/*练习10.19:用 stable_partition 重写前一题的程序,与 stable_sort 类似,在
划分后的序列中维持原有元素的顺序。*/
void biggies(vector<string>& words, vector<string>::size_type sz);//函数声明
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
Show(svec);
system("pause");
return 0;
}
void biggies(vector<string>& words, vector<string>::size_type sz)
{
sort(words.begin(), words.end());//排序
words.erase(unique(words.begin(), words.end()), words.end());//删除重复内容
stable_sort(words.begin(), words.end(), [](const string& s1,
const string& s2) {return s1.size() < s2.size(); });
/*auto it = partition(words.begin(), words.end(), [sz](const string& s) {return s.size() >= sz; });
//partition返回最后一个为true的元素之后的位置
auto count = it-words.begin();
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(words.begin(),it,
[](const string& s) {cout << s << " "; }); */
/*输出
3 words of length 5 or longer
turtle quick jumps
turtle quick jumps over slow the red fox
*/
auto it = stable_partition(words.begin(), words.end(), [sz](const string& s) {return s.size() >= sz; });
//stable_partition可以保持原来的顺序
auto count = it - words.begin();
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(words.begin(), it,
[](const string& s) {cout << s << " "; });
/*输出
3 words of length 5 or longer
jumps quick turtle
jumps quick turtle fox red the over slow
*/
cout << endl;
}
=====================================================================
第10章 泛型算法 352页 lambda捕获和返回
=====================================================================
//QQ108201645编写
#include<iostream>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;
//值捕获
void fcn1()
{
size_t v1 = 42;//局部变量
//将v1拷贝到名为f的可调用对象
auto f = [v1] {return v1; };//下标内捕获v1的值
v1 = 0;
auto j = f();//j为42;f保存了我们创建它时v1的拷贝
}
//引用捕获
void fcn2()
{
size_t v1 = 42;//局部变量
//将v1拷贝到名为f的可调用对象
auto f2 = [&v1] {return v1; };//捕获引用地址
v1 = 0;
auto j = f2();//j为42;f保存了我们创建它时v1的拷贝
}
void biggies(vector<string> &words,
vector<string>::size_type sz,
ostream &os = std::cout, char c = ' ')
{
//与之前一样的重排words的代码
sort(words.begin(), words.end());
words.erase(unique(words.begin(), words.end()), words.end());
stable_sort(words.begin(), words.end(), [](const string& s1,
const string& s2) {return s1.size() < s2.size(); });
//打印count的语句改为打印到os
for_each(words.begin(), words.end(),
[&os, c](const string& s) {os << s << c; });
cout << endl;
}
int main()
{
fcn1();
fcn2();
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
system("pause");
return 0;
}
=====================================================================
#include<iostream>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;
void biggies(vector<string> &words,
vector<string>::size_type sz,
ostream &os = std::cout, char c = ' ')
{
//与之前一样的重排words的代码
sort(words.begin(), words.end());
words.erase(unique(words.begin(), words.end()), words.end());
auto it = find_if(words.begin(), words.end(), [=](const string& s)
{return s.size() >= sz; });
//os隐式捕获,引用捕获方式;c显式捕获,值捕获方式
for_each(words.begin(), words.end(),
[&, c](const string& s) {os << s << c; });
cout << endl;
//os显式捕获,引用捕获方式;c隐式捕获,值捕获方式
for_each(words.begin(), words.end(),
[=, &os](const string& s) {os << s << c; });
}
#ifdef DECLARATION
速记:
[ ]空捕获,{}里的内容根据parameter list的参数调用
[ names ],names代表值捕获(捕获内容的改变不影响调用),如果是&names是引用方式捕获
[ & ] 隐式引用捕获方式
[ = ] 隐式值捕捞方式
[&, ldentifier_list]除了ldentifier_list是显式,值捕获,函数体任何调用的变量都是隐式引用捕获
[=, ldentifier_list]除了ldentifier_list是显示值捕获或加上&变成显式,引用捕获方式,函数体任何调用的变量都是隐式值捕获
#endif
int main()
{
vector<string> svec{ "the", "quick", "red", "fox",
"jumps", "over", "the", "slow", "red", "turtle" };
biggies(svec, 5);
system("pause");
return 0;
}
=====================================================================
表10.1:lambda捕获列表 | |
[ ] | 空捕获列表。lambda不能使用所在函数中的变量。一个lambda只有捕获变量后才能使用它们 |
[names] | names是一个逗号分隔的名字列表,这些名字都是lambda所在函数的局部变量。默认情况下,捕获列表中的变量都被拷贝。名字前如果使用了&,则采用引用捕获方式 |
[ & ] | 隐式捕获列表,采用引用捕获方式。lambda体中所使用的来自所在函数的实体都采用引用方式捕获 |
[ = ] | 隐式捕获列表,采用值捕获方式。lambda体将拷贝所使用的来自所在函数的实体的值 |
[ &, ldentifier_list ] | ldentifier_list是一个逗号分隔的列表,包含0个或多个来自所在函数的变量。这些变量采用值捕获方式,而任何隐式捕获的变量都采用引用方式捕获。identifier_list中的名字前面不能使用& |
[ =, ldentifier_list ] | ldentifier_list中的变量都采用引用方式捕获,而任何隐式捕获的变量都采用值方式捕获。identifier_list中的名字不能包括this,且这些名字之前必须使用& |
=====================================================================
第10章 泛型算法 352页 可变lambda
=====================================================================
//QQ108201645编写
#include <iostream>
using namespace std;
#ifdef DECLARATION
void Test()
{
size_t v1 = 42;
//f可以改变它所捕获的变量的值
auto f = [v1](){return v1++; };//错误,如果不加mutable则为不可变lambda
v1 = 0;
auto j = f();//j 为43
}
#endif
//可变lambda
int fcn3()
{
size_t v1 = 42;
//f可以改变它所捕获的变量的值
auto f = [v1]()mutable {return ++v1; };
v1 = 0;//值捕获后改变vi的值不改变f()里面返回的值
auto j = f();//j 为43
return j;
}
int fcn4()
{
size_t v1 = 42;
//v1是一个非const变量的引用
//可以通过f2中的引用来改变它
auto f2 = [&v1]()mutable {return ++v1; };//一个引用捕获的变量可以进行可变操作
v1 = 0;//改变f2()里v1的值
auto j = f2();//j的值为0然后自增等于1
return j;
}
int main()
{
//Test();
cout << fcn3() << endl;
cout << fcn4() << endl;
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 353页 指定lambda返回类型
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void Test()
{
vector<int> ivec{ 1,2,3,4,5 };
find_if(ivec.begin(),ivec.end(),[](int i) {return i < 3 ? -i : i; });//并不会改变里央的内容
find_if(ivec.begin(), ivec.end(), [](int i){return i < 3 ? -i : i; });
for_each(ivec.begin(), ivec.end(), [](int i) {cout << i << " "; });
cout << endl;
}
int main()
{
Test();
vector<int> ivec{ 1,2,3,4,5 };
/*transform接受三个迭代器和一个可调用对象,前两个表示序列,第三个表示目前位置
算法对输入序列中的每个元素调用 可调用对象,并将结果写到目的位置*/
transform(ivec.begin(), ivec.end(), ivec.begin(),
[](int i) {return i < 3 ? -i : i; });//小于3的数改为负数
for_each(ivec.begin(), ivec.end(), [](int i) {cout << i << " "; });
cout << endl;
//错误不能推断的lambda的返回类型
transform(ivec.begin(), ivec.end(), ivec.begin(),
[](int i) { if (i < 0) return -i; else return i; });//vs2017编译通过
for_each(ivec.begin(), ivec.end(), [](int i) {cout << i << " "; });
/*
func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int(*)[10];
尾返回类型跟在形参列表并以一个->符号开头。为了表示函数真正的返回类型跟在形参列表之后
*/
transform(ivec.begin(), ivec.end(), ivec.begin(),
[](int i)->int
{if (i < 0)return -i; else return i; });
for_each(ivec.begin(), ivec.end(), [](int i) {cout << i << " "; });
cout << endl;
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 354页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
/*练习10.20:标准库定义了一个名为 count_if 的算法。类似 find_if,此函数接受
一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中每个元素执行。
count_if返回一个计数值,表示谓词有多少次为真。使用count_if重写我们程序中
统计有多少单词长度超过6的部分。*/
vector<string> svec{ "ok very good","hello","I like C++", };
auto num = count_if(svec.begin(), svec.end(),
[](const string& s) {return s.size()>=6; });
cout << num << endl;
/*练习10.21:编写一个 lambda,捕获一个局部 int 变量,并递减变量值,直至它变为0。
一旦变量变为0,再调用lambda应该不再递减变量。lambda应该返回一个bool值,指
出捕获的变量是否为0。*/
void mutable_lambda();//函数声明
mutable_lambda();//函数调用
system("pause");
return 0;
}
void mutable_lambda()
{
int vi = 5;
auto f = [=]()mutable->bool
{
if (vi > 0)
{
vi--;
return false;
}
else
return true;
};
for (int j = 0; j < 6; j++)
cout << f() << " ";
cout << endl;
}
=====================================================================
第10章 泛型算法 354页 参数绑定
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>//bind所在的头文件
using namespace std;
using std::placeholders::_1;// _1对应声明后才能使用_1
bool check_size(const string& s, string::size_type sz)
{
return s.size() >= sz;
}
void Show(vector<string>& v)
{
for_each(v.begin(), v.end(), [](const string& s) {cout << s << " "; });
cout<<endl;
}
int main()
{
//_1表示第一个参数,_2表示第二个参数依此类推
//标准库bind函数
string s = "hello";
auto check6 = bind(check_size, placeholders::_1, placeholders::_2);
bool bl = check6(s,6);//会调用check_size(s,6)
vector<string> svec{ "hello","world","good" };
auto it = find_if(svec.begin(), svec.end(), bind(check_size, placeholders::_1, 5));
cout << *it << endl;
Show(svec);
string::size_type sz = 5;
//auto wc = find_if(svec.begin(), svec.end(),[sz](const string& s) {s.size() >= sz; });
//可以替换成如下使用check_size的版本
auto wc = find_if(svec.begin(), svec.end(), bind(check_size, _1, sz));
// _n名字都定义在一个名为placeholders的命名空间中
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 354页 bind的参数绑定
=====================================================================
//QQ108201645编写
#include <iostream>
#include <functional>
#include <vector>
using std::bind;
//使用placeholders
using namespace std::placeholders;
using std::placeholders::_1; using std::placeholders::_2;//也可以用这个,等同于上面
using namespace std;
int main()
{
//g是一个可有两个参数的可调用对象
auto f = [](int a,int b,int c,int d,int e)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
cout << "e = " << e << endl;
return a+b+c+d+e;
};
int a = 1, b = 2, c = 3;
auto g = bind(f, a, b, _2, c, _1);
/*
g(_1,_2)
映射为
f(a,b,_2,c,_1)
g(X,Y)
将变成
f(a,b,Y,c,X)
*/
cout << g(4, 5) << endl;
/*cout << typeid(g).name() << endl;*/
system("pause");
return 0;
}
/*
输出内容
a = 1
b = 2
c = 5
d = 3
e = 4
15
*/
=====================================================================
//QQ108201645编写
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
void ShowArr(int* beg, int* end)
{
while (beg != end)
{
cout << *beg++ << " ";
}
cout << endl;
}
int main()
{
int arr[] = { 11,22,4,65,77,41,224,35,68 };
auto isShorter = [](int a, int b) {return a < b; };
stable_sort(begin(arr), end(arr), isShorter);//从小到大排序
ShowArr(begin(arr), end(arr));
stable_sort(begin(arr), end(arr), bind(isShorter, _2, _1));//从大到小排序
ShowArr(begin(arr), end(arr));
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 356页 bind的参数重排
=====================================================================
//QQ108201645编写
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
ostream& print(ostream& os, const string& s, char c)
{
return os << s << c;
}
int main()
{
vector<string> svec = { "abcef","def","hello","good","world" };
auto isShorter = [](const string& s, const string& s1) {return s.size() < s1.size(); };
sort(begin(svec), end(svec), isShorter);
//错误,不能拷贝os
//for_each(begin(svec), end(svec), bind(print, cout, _2, ' '));
/*如果我们希望传递给bind一个对象而又不拷贝它,就必须使用标准库ref函数,
函数返回一个对象,包含给定的引用,此对象是可以拷贝的,标准库中还有一个cref函数,生成一个保存const
的类,与bind一样,函数ref和cref也定义在functional头文件中*/
for_each(begin(svec), end(svec), bind(print, ref(cout), _1, ' '));
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 357页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
bool isSize(const string& s, string::size_type sz)
{
return s.size() < sz;
}
ostream& print(ostream& os, const string& s, char c)
{
return os << s << c;
}
int main()
{
vector<string> svec = { "identifier","parenthesis","hello","good","world","123456" };
auto isShorter = [](const string& s, const string& s1) {return s.size() < s1.size(); };
stable_sort(begin(svec), end(svec), isShorter);
for_each(svec.begin(), svec.end(), bind(print, ref(cout), _1, ' '));
cout << endl;
/*练习10.22:重写统计长度小于等于6的单词数量的程序,使用函数代替 lambda。*/
string::size_type sz = 6;
/*lambda方式*/
/*auto isSize = [=](const string& s) {return s.size() < sz; };
auto cnt = count_if(svec.begin(), svec.end(),isSize); */
auto cnt = count_if(svec.begin(), svec.end(),/*isSize*/ bind(isSize,_1,sz));
cout << "长度小于6的单词数量:" << cnt << endl;
for_each(svec.begin(), svec.end(), bind(print,ref(cout),_1,' '));
cout << endl;
/*练习10.23:bind 接受几个参数?
bind参数是可变参数,第一个是可调用对象,即实际工作函数A,返回供算法使用的新的可调用对象B。若A接受X
个参数,则bind的参数是X+1,即除A外,其他参数应对应A所接受的参数,这些参数一部分来自于B(_n),另外一
些来自所处函数的局部变量*/
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
//如果ctr的值大于1,返回word的复数形式(201页内容)
string make_plural(size_t ctr, const string &word,
const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
bool check_size(const string& s, size_t len)
{
return s.size() <= len;
}
void biggis(vector<int>& v, const string& s)
{
auto it = find_if(v.begin(), v.end(), bind(check_size, s, _1));
if (it != v.end())
cout << "位置:" << (it - v.begin()) + 1 << " 大于" << s << "的长度" << endl;
else
cerr << "找不到!" <<"比"<<s<<"长度 大的元素"<< endl;
}
void biggis(vector<string>& words, vector<string>::size_type sz)
{
sort(words.begin(), words.end());//排序
words.erase(unique(words.begin(), words.end()), words.end());//删除重复单词
stable_sort(words.begin(), words.end(), [](const string& a,
const string& b) {return a.size() < b.size(); });
auto it = partition(words.begin(), words.end(), bind(check_size, _1, sz));
auto count = it - words.begin();
cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer" << endl;
for_each(words.begin(), words.end(), [](const string& s) {cout << s << " "; });
cout << endl;
}
int main()
{
/*练习10.24:给定一个string,使用 bind 和 check_size 在一个 int 的vector
中查找第一个大于string长度的值。*/
vector<int> ivec{ 1,2,3,4,5,6,7,8,9,10 };
biggis(ivec, "hello");
biggis(ivec, "world");
biggis(ivec, "const string ");
/*练习10.25:在10.3.2节(第349页)的练习中,编写了一个使用partition 的biggies
版本。使用 check_size 和 bind 重写此函数。*/
vector<string> svec{ "hello","the","what","furniture" };
biggis(svec, 6);
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 358页 再探迭代器
=====================================================================
//QQ108201645编写
·插入迭代器( insert iterator ): 这些迭代器被绑定在到一个容器上,可用来向容器插入元素。
·流迭代器( stream iterator ): 这些迭代器被绑定到输入或输出流上,可用来遍历所有关联IO流。
·反向迭代器( reverse iterator ): 这些迭代器向后而不是向前移动。除了forward_list之外的标准库都有反向迭代器
·移动迭代器( move iterator ): 这些专用的迭代器不是拷贝其中的元素,而是移动它们,第13.6.2节(第480页)介绍移动迭代器
表10.2:插入迭代器操作 | |
it = t | 在it指定的当前位置插入t。假定c是it绑定的容器,依赖于插入迭代器的不同种类,此赋值会分别调用c.push_back(t)、c.push_front(t)或c.insert(t,p),其中p为传递给inserter的迭代器位置 |
*it,++it,it++ | 这些操作虽然存在,但还会对it做任何事情。每个操作都返回it |
插入迭代器有三种类型差异在于元素插入的位置
·back_inserter(参见10.2.2节,第341页)创建一个push_back的迭代器
·front_inserter创建一个使用push_front的迭代器
·inserter创建一个使用insert的迭代器。此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前
只有在容器支持push_front的情况下,我们才可以使用front_inserter。类型的,只有在容器支持push_back的情况下,才能使用back_isnerter。
=====================================================================
第10章 泛型算法 358页 再探迭代器
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
int main()
{
int val = 10;
list<int> ivec{ 1,2,3 };
list<int>::iterator iter = ivec.begin();
//当调用这个时获得一个迭代器
#ifdef DECLARATION
auto it = inserter(ivec, iter);//it在begin()之前
#endif
insert_iterator<list<int>> insert_it(ivec, iter);
*insert_it = val;
cout << typeid(insert_it).name() << endl;
for_each(ivec.begin(), ivec.end(), [](int num) {cout << num << " "; });
//等价于下面
auto it1 = ivec.begin();
it1 = ivec.insert(it1, ++val);
++it1;
cout << "\n插入11之后的位置的元素:" << *it1 << endl;
for_each(ivec.begin(), ivec.end(), [](int num) {cout << num << " "; });
cout << endl;
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
void Show(list<int>& l)
{
for (auto i : l)
cout << i << " ";
cout << endl;
}
int main()
{
list<int> lst = { 1,2,3,4 };
list<int> lst2, lst3, lst4;
//拷贝完成之后,lst2包含4 3 2 1
copy(lst.begin(), lst.end(), front_inserter(lst2));
//拷贝完成之后,lst3包含1 2 3 4
copy(lst.cbegin(), lst.cend(), inserter(lst3,lst3.begin()));
//同上
copy(lst.begin(), lst.end(), back_inserter(lst4));
cout << "lst = "; Show(lst);
cout << "lst2 = "; Show(lst2);
cout << "lst3 = "; Show(lst3);
cout << "lst4 = "; Show(lst4);
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 359页 练习题
=====================================================================
//QQ108201645编写
/*
练习10.26:解释三种插入迭代器的不同之处。
back_inserter尾部插入,要求支持push_back操作
front_inserter首部插入,要求支持front_inserter操作
inserter 插入到指定位置
*/
#include <iostream>
#include <list>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
void ShowVec(vector<int>& v)
{
for (auto i : v)
cout << i << " ";
cout << endl;
}
void ShowList(list<int>& l)
{
for (auto i : l)
cout << i << " ";
cout << endl;
}
int main()
{
/*
练习10.27:除了 unique(参见10.2.3节,第343页) 之外,标准库还定义了名为
unique_copy 的函数,它接受第三个迭代器,表示拷贝不重复元素的目的位置。编写
一个程序,使用 unique_copy将一个vector中不重复的元素拷贝到一个初始化为空的
list中。
*/
vector<int> ivec = { 1,2,3,3,4,5 };
list<int> lst;
unique_copy(ivec.begin(), ivec.end(), back_inserter(lst));
ShowVec(ivec);//输出 1 2 3 3 4 5
ShowList(lst);//输出 1 2 3 4 5
/*练习10.28:一个vector 中保存 1 到 9,将其拷贝到三个其他容器中。分别使用
inserter、back_inserter 和 front_inserter 将元素添加到三个容器中。对每
种 inserter,估计输出序列是怎样的,运行程序验证你的估计是否正确。
*/
ivec.clear();
lst.clear();
ivec.assign({ 1,2,3,4,5,6,7,8,9 });
ShowVec(ivec);//输出 1 2 3 4 5 6 7 8 9
unique_copy(ivec.begin(), ivec.end(), inserter(lst, lst.begin()));
ShowList(lst);//输出1 2 3 4 5 6 7 8 9
unique_copy(ivec.begin(), ivec.end(), back_inserter(lst));
ShowList(lst);//输出1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
unique_copy(ivec.begin(), ivec.end(), front_inserter(lst));
ShowList(lst);//输出9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 359页 iostream迭代器
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
/*
iterator文件头
istream_iterator读取输入流
ostream_iterator向一个输出流写数据
*/
int main()
{
fstream on("1.txt");
on << "abcdefghijklmnopqrstuvwxyz" << endl;
on.close();
istream_iterator<int> int_it(cin);//从cin读取int
istream_iterator<int> int_eof;//尾后迭代器
ifstream in("1.txt");
istream_iterator<string> str_it(in);//从1.txt读取字符串
in.close();
//下面是用istream_iterator从标准输入读取数据,存入一个vector的例子
vector<int> vec;
istream_iterator<int> in_iter(cin);//从cin读取int
istream_iterator<int> eof;//istream尾后迭代器
while (in_iter != eof)
{
//后置递增运算读取流,返回迭代器的旧值
//解引用迭代器、获得从流读取的前一个值
vec.push_back(*in_iter++);
}
system("pause");
return 0;
}
=====================================================================
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using namespace std;
/*
iterator文件头
istream_iterator读取输入流
ostream_iterator向一个输出流写数据
*/
int main()
{
istream_iterator<int> in_iter(cin), eof;//循环输入,以ctrl+z结束,从cin读取int
vector<int> vec(in_iter, eof);//从迭代器范围构造vec
for_each(vec.begin(), vec.end(), [](int i) {cout << i << " "; });
system("pause");
return 0;
}
=====================================================================
表10.3:istream_iterator操作 | ||
istream_iterator<T> in (is); | in从输入流is读取类型为T的值 | |
istream_iterator<T> end; | 读取类型为T的值的istream_iterator迭代器,表示尾后位置 | |
in1 == in2 | in1和in2必须读取相同类型。如果它们都是尾后迭代器,或绑定的输入,则两者相同 | |
in1 != in2 | ||
*in | 返回从流中读取的值 | |
in->mem | 与(*in).mem的含义相同 | |
++in, in++ | 使用元素类型所定义的>>运算符从输入流中读取下一个值。与以往一样,前置版本返回一个指向递增后迭代器的引用,后置版本返回旧值 | |
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <numeric>
using namespace std;
int main()
{
istream_iterator<int> in(cin), eof; //从cin读取int
cout << accumulate(in, eof, 0) << endl; //每调用一次in就是一次输入,循环输入,以ctrl+z结束,
system("pause");
return 0;
}
/*
如果输入为
23 109 45 89 6 34 12 90 34 23 56 23 8 89 23 ^Z
则输出
664
请按任意键继续. . .
*/
=====================================================================
//QQ108201645编写
表10.4:ostream_iterator操作 | ||
ostream_iterator<T> out (os); | out将类型为T的值写到输出流os中 | |
ostream_iterator<T> out (os,d); | out将类型为T的值写到输出流os中,每个值后面都输出一个d。d指向一个空字符结尾的字符数组 | |
out = val | 用<<运算符将val写入到out所绑定的ostream中。val的类型必须与out可写的兼容类型 | |
*out, ++out, out++ | 这些运算符是存在的,但不对out做任何事情。每个运算符都返回out | |
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
int main()
{
vector<int> vec{ 1,2,3 };
//用ostream_iterator来输出值的序列
ostream_iterator<int> out_iter(cout, " ");//将每个元素写到cout,每个元素后加空格
for (auto e : vec)
*out_iter++ = e;//输出值的序列
//向out_iter赋值时,可以忽略引用和递增运算。out_iter++ = e也可以,或out_iter=e
cout << endl;
//可以通过copy来打印vec中的元素,这比编写循环更简单
copy(vec.begin(), vec.end(), out_iter);
cout << endl;
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 359页 使用流迭代器处理类类型
=====================================================================
//QQ108201645编写
//保存为Sales_data.h头文件
#ifndef _SALES_DATA_H_
#define _SALES_DATA_H_
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
/*定义在public:说明符之后的成员在整个程序内可被访问public成员定义类的
接口*/
/*定义在private:说明符之后成员只被类的函数访问,但不能被使用
该类的代码访问,private封装了(即隐藏了)类的实现细节*/
//使用class而非struct开始类的定义,只是形式不同,唯一区别就是默认访问权限不同
//没有定义public: protected: private: 的情况下.在struct里都是public
class Sales_data
{
public://公有成员
//新增构造函数(不同的类内初始化方式)
Sales_data() = default;//默认构造函数可以声明在类类部,也可以作为定义出现在类的外部
explicit Sales_data(const std::string &s, unsigned n, double p) :
bookNo(s), units_sold(n), revenue(p*n) {}
/*Sales_data(std::istream& is)
{
read(is, *this);
}*/
//保留默认构造函数
explicit Sales_data(std::string s)
:bookNo(s) {}//bookNo(s)表示构造函数列表初始化(构造函数初始值列表)
//只允许出现在类内声明构造函数时使用explicit
explicit Sales_data(std::istream& is)
{
read(is, *this);
}
friend Sales_data add(const Sales_data&, const Sales_data&);
#ifdef DECLARATION
添加一个+=重载
#endif
Sales_data& operator+=(const Sales_data& rhs)
{
return combine(rhs);//直接调用combine加法
}
friend std::istream& read(std::istream&, Sales_data&);
friend std::ostream& print(std::ostream&, const Sales_data&);
friend ifstream& read(ifstream& in, Sales_data& item)
{
double price = 0;
in >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return in;
}
friend ofstream& print(ofstream& out, const Sales_data& item)
{
out << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return out;
}
friend std::istream& operator>>(std::istream& is, Sales_data&);//operator>>重载,支持cin>>对象名接收
friend std::ostream& operator<<(std::ostream& os, const Sales_data&);//operator<<重载,支持cin>>对象名直接输出内容
//之前已有的其它成员
std::string isbn() const;
Sales_data& combine(const Sales_data&);
private://私有成员
double ave_price()const;
std::string bookNo;
unsigned units_sold = 0;//c++11开始支持类体内初始化(变量名译:单独售出)
double revenue = 0.0;//初始化revenue(译:财政收入)
};//这里要加分号
Sales_data add(const Sales_data &lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;//把lhs的数据拷贝给sum
sum.combine(rhs);//把rhs的数据成员加到sum当中
return sum;
}
//定义read和print函数
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
cout << "输入书的编号、售出数量、单价" << endl;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price() << endl;
return os;
}
//上面两个等同于operator>>与operator<<重载
std::istream& operator>>(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& operator<<(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.ave_price();
return os;
}
std::string Sales_data::isbn() const
{
//return bookNo;//用于返回Sales_data的数据成员
return this->bookNo;//同上
//默认情况this指针指向非常量的常量指针
}
//函数combine设计初衷类型复合赋值运算符+=
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;//把rhs的成员加到this对象的成员上
revenue += rhs.revenue;
return *this;//返回调用该函数的对象
}
double Sales_data::ave_price()const
{
return units_sold ? revenue / units_sold : 0;
}
#endif
―――――――――――――――――――――――――――――――――――――――
//QQ108201645编写
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <vector>
#include "Sales_data.h"
using namespace std;
int main()
{
istream_iterator<Sales_data> item_iter(cin), eof;
ostream_iterator<Sales_data> out_iter(cout, "\n");
//将第一笔交易存在sum中,并读取下一条记录
Sales_data sum = *item_iter++;
while (item_iter!=eof)
{
//如果当前交易记录(存在item_iter中)有着相同的ISBN号
if (item_iter->isbn() == sum.isbn())
sum += *item_iter++;//将其加到sum上并读取下一条记录(要添加+=运算符重载)
else
{
out_iter = sum;//输出当前sum值
sum = *item_iter++;//读取下一条记录
}
}
out_iter = sum;//记得打印最后一组记录的和
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 362页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;
int main()
{
/*练习10.29:编写程序,使用流迭代器读取一个文本文件,存入一个vector中的string
里。*/
string FileName = "1.txt";
if (remove(FileName.c_str()) == 0)//如果已有文件则删除
{
cout << FileName << "删除成功" << endl;
}
fstream in(FileName);
in.open(FileName,ios::out);
if (!in)
cerr << "创建文件" << endl;
in << "123456789" << endl;//只存入这个
in << "hello" << endl;
in.close();
in.open(FileName);
if (!in)
cerr << "打开文件失败" << endl;
istream_iterator<string> iter(in);
istream_iterator<string> iter_eof;//尾后迭代器
in.close();
vector<string> svec;
while (iter != iter_eof)
{
svec.push_back(*iter++);
}
ostream_iterator<string> out(cout);
copy(svec.begin(), svec.end(), out);//输出svec
cout << endl;
in.open(FileName);
if (!in)
cerr << "打开文件失败" << endl;
ostringstream os;
os << in.rdbuf();//读取全部
cout << "输出\n" << os.str() << endl;
string s = os.str();
//out = in.rdbuf();//错误
out = os.str();
in.close();
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
/*练习10.30:使用流迭代器、sort 和 copy 从标准输入读取一个整数序列,将其排序,
并将结果写到标准输出。*/
istream_iterator<int> iter(cin), eof;
vector<int> ivec{ iter,eof };//迭代器范围构造ivec (每次调用iter都会调用输入,用ctrl+z结束输入)
sort(ivec.begin(), ivec.end());//排序
ostream_iterator<int> out(cout, " ");//每个元素后面加一个空格
//copy(ivec.begin(), ivec.end(), out);//输出内容
/*练习10.31:修改前一题的程序,使其只打印不重复的元素。你的程序应该使用
unique_copy(参见10.4.1节,第359页)。*/
//将上面代码改为
unique_copy(ivec.begin(), ivec.end(), out);
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <numeric>
using namespace std;
#ifndef SALESITEM_H//未定义SALESITEM_H则继续向下执义
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
#if defined(IN_CLASS_INITS) && defined(DEFAULT_FCNS)
Sales_item() = default;
#else
Sales_item() : units_sold(0), revenue(0.0) { }
#endif
Sales_item(const std::string &book)
:bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const
{
return bookNo;
}
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
#ifdef IN_CLASS_INITS
unsigned units_sold = 0; // explicitly initialized
double revenue = 0.0;
#else
unsigned units_sold;
double revenue;
#endif
};
// used in chapter 10
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool operator==(const Sales_item &lhs, const Sales_item &rhs)//==运算符重载
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)//'+='重载
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs)//'+'重载
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|) 调用+=重载
return ret; // return (|ret|) by value 返回临时对象
}
std::istream& operator>>(std::istream& in, Sales_item& s)//重载输入运算符
{
double price;
in >> s.bookNo >> s.units_sold >> price;//接受书的编号、数量、价格
// check that the inputs succeeded
if (in)//输入不等于空、比如输入ctrl+z再回车
s.revenue = s.units_sold * price;//收入等于数量乘价格
else
s = Sales_item(); // input failed: reset object to default state
//调用构造函数重置为默认。
return in;
}
std::ostream& operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)//除数不等于0
return revenue / units_sold;
else
return 0;
}
#endif
bool comIsbn(Sales_item &s1, Sales_item &s2)
{
return s1.isbn() < s2.isbn();
}
int main()
{
/*练习10.32:重写1.6节(第21页)中的书店程序,使用一个vector保存交易记录,
使用不同算法完成处理。使用 sort 和10.3.1节(第345页)中的 compareIsbn 函数
来排序交易记录,然后使用 find 和 accumulate 求和。*/
vector<Sales_item> vs;
istream_iterator<Sales_item> in_iter(cin), eof;
//读入交易记录,存入vector
while (in_iter!=eof)
{
vs.push_back(*in_iter++);
}
if (vs.empty())
{
cerr << "No data?!" << endl;
return -1;//表示失败
}
sort(vs.begin(), vs.end(), comIsbn);//comIsbn要自己加一个函数才不会出错
auto beg = vs.begin();
while (beg!=vs.end())
{
auto item = *beg;//相同ISBN的交易记录中的第一个
//在后续记录中查找第一个ISBN与item不同者
auto r = find_if(beg + 1, vs.end(),//满足第一个不同的isbn号的
[item](const Sales_item& item1)
{return item1.isbn() != item.isbn(); });
//将范围(beg,r)间的交易记录累加输出
cout << accumulate(beg + 1, r, item) << endl;
//指向下一段交易记录的第一个
beg = r;
}
system("pause");
return 0;
}
=====================================================================
#include <iostream>
#include <iterator>
#include <fstream>
#include <algorithm>
using namespace std;
int main(int argc,char* argv[])
{
/*练习10.33:编写程序,接受三个参数:一个输入文件和两个输出文件的文件名。输入
文件保存的应该是整数。使用 istream_iterator 读取输入文件。使用
ostream_iterator 将奇数写入第一个输入文件,每个值后面都跟一个空格。将偶数
写入第二个输出文件,每个值都独占一行。*/
if (argc != 4)
{
cout << "用法:execise.exe in_file"
"out_file1 out_file2" << endl;
return -1;
}
ifstream in(argv[1]);
if (!in)
{
cout << "打开输入文件失败" << endl;
exit (1);
}
ofstream out1(argv[2]);
if (!out1)
{
cout << "打开输出文件1失败" << endl;
exit(1);
}
ofstream out2(argv[3]);
if (!out2)
{
cout << "打开输出文件2失败" << endl;
exit(1);
}
/*操作方法:首先在cpp编译exe所在目录(我的是vs2017路径C:\Users\Administrator\source\repos\01cpp\Debug)
新建一个1.txt
写入如下内容
1 2 3 4 5 6 7 8 9
写好并保存
然后再对这个文件夹shift+鼠标右键,调出此处dos命令窗口,我的文件是01cpp.exe
那就输入01cpp.exe 1.txt 2.txt 3.txt,写完回车,然后输出一个2.txt与3.txt的结果
*/
//创建流迭代器从文件读入整数与尾后迭代器
istream_iterator<int> in_iter(in), eof;
ostream_iterator<int> out1_iter(out1, " "), out2_iter(out2, "\n");
while (in_iter != eof)
{
if (*in_iter & 1)
*out1_iter++ = *in_iter;
else
*out2_iter++ = *in_iter;
in_iter++;
}
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 363页 反向迭代器
=====================================================================
//QQ108201645编写
/*除了forward_list之外,其他容器都支持反向迭代器。我们可以通过调用rbegin、rend、crbegin和crend成员函数来获得反向迭代器。这些成员函数返回指向容器尾元素和首元素之前一个位置的迭代器。与普通迭代器一样,反向迭代器也有const和非const版本*/
=====================================================================
//QQ108201645编写
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
void Show(vector<int> &vec)
{
for (auto iter = vec.cbegin();//将iter绑定到首元素
iter != vec.cend();//cend指向尾元素之后的位置
++iter)//递增
cout << *iter << " ";
cout << endl;
}
void R_Show(vector<int> &vec)
{
for (auto r_iter = vec.crbegin();//将r_iter绑定到尾元素
r_iter != vec.crend();//crend指向首元素之前的位置
++r_iter)//实际是递减
cout << *r_iter << " ";
cout << endl;
}
//流迭代器不支持递减运算
int main(int argc,char* argv[])
{
vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
R_Show(vec);//reveser打印9到1
sort(vec.begin(), vec.end());//按"正常序"排序vec
Show(vec);//正常打印1到9
sort(vec.rbegin(), vec.rend());//按"逆序"排序vec,最小元素放在vec末尾
Show(vec);//正常打印9到1
system("pause");
return 0;
}
=====================================================================
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main(int argc,char* argv[])
{
string line = "FIRST,MIDDLE,LAST";
//在一个逗号分隔列表中查找第一个元素
auto comma = find(line.cbegin(), line.cend(), ',');
cout << string(line.cbegin(), comma) << endl;
//在一个逗号分隔的列表中查找最后一个元素
auto rcomma = find(line.crbegin(), line.crend(), ',');
//cout << string(line.crbegin(), comma) << endl;//错误:将逆序输出单词的字符
/*如果输入的是:FIRST,MIDDLE,LAST 则这条语句打找印TSAL */
//可以通过reverse_iterator的base成员函数来完成
cout << string(rcomma.base(), line.cend())<<endl;
system("pause");
return 0;
}
=====================================================================
=====================================================================
第10章 泛型算法 365页 练习题
=====================================================================
//QQ108201645编写
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <list>
using namespace std;
int main(int argc,char* argv[])
{
/*练习10.34:使用 reverse_iterator 逆序打印一个vector。*/
vector<int> ivec{ 1,2,3,4,5,6 };
for (vector<int>::reverse_iterator it = ivec.rbegin();
it != ivec.rend(); ++it)
cout << *it << " ";
cout << endl;
/*练习10.35:使用普通迭代器逆序打印一个vector。*/
vector<int>::iterator it = ivec.end();
while(it != ivec.begin())
cout << *(--it) << " ";
cout << endl;
/*练习10.36:使用 find 在一个 int 的list 中查找最后一个值为0的元素。*/
list<int> lst{ 1,2,0,3,4,5,6,7,8,0,7,8 };
ostream_iterator<int> out(cout, " ");//将类型为int的值写到输出流中,每个后面跟着空格
copy(lst.begin(), lst.end(), out);//输出内容
auto f = find(lst.rbegin(), lst.rend(), 0);
cout << endl;
f++;
size_t p = 1;
//从链表头开始遍历,计数最后一个0的编号
for (auto iter = lst.begin(); iter != f.base(); iter++, p++);
if (p >= lst.size())
cout << "容器中没有0" << endl;
else
cout << "最后一个0在第" << p << "个位置" << endl;
/*练习10.37:给定一个包含10 个元素的vector,将位置3到7之间的元素按逆序拷贝到一个list中*/
vector<int> ivec1{ 1,2,3,4,5,6,7,8,9,10 };
list<int> ilst;
auto fval = find(ivec1.begin(), ivec1.end(), 3);//查找3的元素
auto lval = find(ivec1.begin(), ivec1.end(), 7);
++fval;
copy(fval, lval, front_inserter(ilst));//从4开始到6
copy(ilst.begin(), ilst.end(), out);//打印4~6
cout << endl;
//第二种方案
vector<int>::reverse_iterator ra(ivec1.begin() + 2);//轮换为反向迭代器
vector<int>::reverse_iterator rb(ivec1.begin() + 7);
ilst.clear();
copy(rb, ra, back_inserter(ilst));//逆序拷贝
copy(ilst.begin(), ilst.end(), out);//打印3~7
cout << endl;
//第三种方案
ilst.clear();
copy(ivec1.begin() + 2, ivec1.end() - 3, front_inserter(ilst));
copy(ilst.begin(), ilst.end(), out);
cout << endl;
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 365页 泛型算法结构
=====================================================================
//QQ108201645编写
表10.5:迭代器类别 | |
输入迭代器 | 只读,不写;单遍扫描,只能递增 |
输出迭代器 | 只写,不读;单遍扫描,只能递增 |
前向迭代器 | 只读写;多遍扫描,只能递增 |
双向迭代器 | 可读写;多遍扫描,可递增递减 |
随机访问迭代器 | 可读写;多遍扫描,支持全部迭代器运算 |
=====================================================================
第10章 泛型算法 365页 泛型算法结构
=====================================================================
//QQ108201645编写
输入迭代器(input iterator):可以读取序列中的元素。一个输入迭代器必须支持
·用于比较两个迭代器的相等和不相等运算符( == 、! = )
·用于推进迭代器的前置和后置递增运算(++)
·用于读取元素的解引用运算符(*);解引用只会出现在赋值运算符的右侧
·箭头运算符(->),等价于(*it).member,即,解引用迭代器,并提取对象的成员
输出迭代器(output iterator):可以看作输入迭代器功能上的补集----只写而不读元素。输出迭代器必须支持
·用于推进迭代器的前置和后置递增运算(++)
·解引用运算符(*),只出现在赋值运算符的左侧(向一个已经解引用的输出迭代器赋值,就是将值写入它所指向的元素)
前向迭代器(forward iterator):可以读写元素。这类迭代器只能在序列中沿一个方向移动。前向迭代器支持所有输入和输出迭代器的操作,而且可以多次读写同一个元素。因此,我们可以保存前向迭代器的状态,使用前向迭代器的算法可以对序列进行多遍扫描。算法replace要求前向迭代器,forward_list上的迭代器是前向迭代器。
双向迭代器(bidirectional iterator):可以正向 / 反向读写序列中的元素。除了支持所有前向迭代器的操作之外,双向迭代器还支持前置和后置递减运算符(--)。算法reverse要求双向迭代器,除了forward_list之外,其他标准库都提供符合双向迭代器要求的迭代器。
随机访问迭代器(random - access iterator):提供在常量时间内访问序列中任意元素的能力。此类迭代器支持双向迭代器的所有功能,此外还支持如下操作:
·用于比较两个迭代器相对位置的关系运算符(<, <= , >和 >= )
·迭代器和一个整数值的加减运算( + , +=, -, -=), 计算结果是迭代器在序列中前进(或后退)给定整数个元素后的位置
·用于两个迭代器上的减法运算符(-),得到两个迭代器的距离
·下标运算符(iter[n]), 与*(iter[n])等价
算法sort要求随机访问迭代器。array、deque、string和vector的迭代器都是随机访问迭代器,用于访问内置数组元素的指针也是
=====================================================================
第10章 泛型算法 367页 练习题
=====================================================================
/*练习10.38:列出5个迭代器类别,以及每类迭代器所支持的操作。
1.输入迭代器:只读,不写;单遍扫描,只能递增
*iterator, ++iterator, == , != , ->
2.输出迭代器:只写,不读;单遍扫描,只能递增
*iterator, ++iterator
3.前向迭代器:只读写;多遍扫描,只能递增
*iterator, ++iterator, == , != , ->
4.双向迭代器:可读写;多遍扫描,可递增递减
*iterator, ++iterator, --iterator, == , != .->
5.随机访问迭代器:可读写;多遍扫描,支持全部迭代器运算
*iterator, ++iterator, --iterator, == , != .->, <, >, +=, -, iterator[n]
*/
=====================================================================
//QQ108201645编写
/*
练习10.39:list 上的迭代器属于哪类?vector呢?
list的迭代器属于双向迭代器
vector的迭代器属于随机访问迭代器
*/
/*练习10.40:你认为 copy 要求哪类迭代器?reverse 和 unique 呢?
copy要求两个输入和一个输出迭代器
reverse要求双向迭代器
unique要求前向迭代器
*/
=====================================================================
第10章 泛型算法 367页 算法形参模式
=====================================================================
//QQ108201645编写
在任何其他算法分类之上,还有一组参数规范。理解这些参数规范对学习新算法很有帮助――通过理解参数的含义,你可以将注意力集中在算法所做的操作上。大多数算法具有如下4种形式之一
alg(beg, end, other args);
alg(beg, end, dest, other args);
alg(beg, end, beg2, other args);
alg(beg, end, beg2, end2, other args);
其中alg是算法的名字,beg和end表示算法所操作的范围,几乎所有算法都接受一个输入范围,是否有其他参数依赖于要执行的操作。这里列出了常见的一种――dest、beg2和end2,都是迭代器参数,顾名思义,如果用到了这些迭代器参数,它们分别承担指定目的位置和第二个范围的角色。除了这些迭代器参数,一些算法还接受额外的、非迭代器的特定参数
=====================================================================
第10章 泛型算法 368页 算法命名规范
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <iterator>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
bool inCmp(const int i,const int j)
{
return i < j;
}
void Show(list<int>& v)
{
auto it = v.begin();
ostream_iterator<decltype(*it)> out(cout, " ");
copy(v.begin(), v.end(), out);
cout << endl;
}
void Show(vector<int>& v)
{
auto it = v.begin();
ostream_iterator<decltype(*it)> out(cout, " ");
copy(v.begin(), v.end(), out);
cout << endl;
}
int main()
{
list<int> ilst{ 1,1,2,3,4,5 };
unique(ilst.begin(), ilst.end());
Show(ilst);//输出内容1 2 3 4 5 5
unique(ilst.begin(), ilst.end(), [](int a, int b) {return a == b; });
Show(ilst);//输出内容1 2 3 4 5 5
vector<int> ivec{ 1,2,3,4,5 };
auto it = find(ivec.begin(), ivec.end(), 4);
cout << (it - ivec.begin() + 1) << endl;//输出内容5
it = find_if(ivec.begin(), ivec.end(), [](int i) {return i == 4; });
cout << (it - ivec.begin() + 1) << endl;//输出内容5
Show(ivec);//输出内容 1 2 3 4 5
reverse(ivec.begin(), ivec.end());//反转元素
Show(ivec);//输出内容5 4 3 2 1
vector<int> ivec1, ivec2;
reverse_copy(ivec.begin(), ivec.end(), inserter(ivec1,ivec1.begin()));
Show(ivec1);//输出内容1 2 3 4 5
//将ivec1中删除奇数元素
#ifdef DECLARATION
remove_if(ivec1.begin(), ivec1.end(),
[](int i) {return i % 2; });
Show(ivec1);//输出内容2 4 3 4 5并不能真正有效的删除残余元素
cout << ivec1.size() << endl;//大小:6
#endif
ivec1.erase(remove_if(ivec1.begin(), ivec1.end(),
[](int i) {return i & 1; }),ivec1.end());
Show(ivec1);//输出内容2 4
Show(ivec);//输出内容5 4 3 2 1
//将偶数元素ivec拷贝到ivec2
remove_copy_if(ivec.begin(), ivec.end(), back_inserter(ivec2),
[](int i) {return i % 2; });
Show(ivec2);//输出内容4 2
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>//inserter所在头文件
using namespace std;
void Show(vector<int>& v)
{
for (auto i : v)
cout << i << " ";
cout<<endl;
}
int main()
{
/*练习10.41:仅根据算法和参数的名字,描述下面每个标准库算法执行什么操作:
replace(beg, end, old_val, new_val); //替换beg和end指定范围内所有old_val的值为new_val
replace_if(beg, end, pred, new_val); //替换beg和end指定范围内使得pred为真的所有元素的值为new_val
replace_copy(beg, end, dest, old_val, new_val); //将beg和end指定范围内的所有old_val替换为new_val,并将新的序列写入到dest指定的容器
replace_copy_if(beg, end, dest, pred, new_val); //将beg和end指定范围内使得pred为真的所有元素的值替换为new_val,并将新的序列写入到dest指定的容器
*/
vector<int> ivec{ 1,2,3,1,2,3 };
replace(ivec.begin(), ivec.end(), 2, 20);//查找值为2的元素,替换成20
Show(ivec);//输出内容1 20 3 1 20 3
replace_if(ivec.begin(), ivec.end(), [](int i) {return i == 3; }, 30);//查找值为3的元素,替换成30
Show(ivec);//输出内容1 20 30 1 20 30
vector<int> ivec1, ivec2;
replace_copy(ivec.begin(), ivec.end(), inserter(ivec1,ivec1.begin()), 1, 10);//dest 是一个指向容器的迭代器
//把ivec的内容拷贝到ivec1,值为1的元素,替换成10
Show(ivec1);//输出内容10 20 30 10 20 30
replace_copy_if(ivec1.begin(), ivec1.end(),back_inserter(ivec2),
[](int i) {return i == 10 || i == 20 || i == 30; }, 5);
//把ivec1的内容拷贝到ivec2, 值为10、20、30的元素, 替换成5
Show(ivec2);//输出内容5 5 5 5 5 5
cout << "输出全部内容" << endl;
Show(ivec);//输出内容1 20 30 1 20 30
Show(ivec1);//输出内容10 20 30 10 20 30
Show(ivec2);//输出内容5 5 5 5 5 5
system("pause");
return 0;
}
=====================================================================
第10章 泛型算法 369页 特定容器算法
=====================================================================
//QQ108201645编写
表10.6:list和forward_list成员函数版本的算法 | |
这些操作都返回void | |
lst.merge ( lst2 ) | 将来自lst2的元素合并入lst。lst和lst2都必须是有序的。 |
lst.merge ( lst2,comp) | 元素将从lst2中删除。在合并之后,lst2变为空。第一个版本使用<运算符;第二个版本使用给定的比较操作 |
lst.remove ( val ) | 调用erase删除掉与给定值相等 ( == ) 或令一元谓词为真的第个元素 |
lst.remove_if ( pred ) | |
lst.reverse ( ) | 反转lst中元素的顺序 |
lst.sort ( ) | 使用<或给定比较操作排序元素 |
lst.sort (comp) | |
lst.unique ( ) | 调用erase删除同一个值的连续拷贝。第一个版本使用==;第二个版本使用给定的二元谓词 |
lst.unique (pred) |
splice成员
表10.7: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不能指向给定范围中元素 |
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <iterator>
#include <functional>
#include <algorithm>
using namespace std;
typedef list<int> IST;
bool inCmp(const int i,const int j)
{
return i < j;
}
void Show(IST& v)
{
auto it = v.begin();
ostream_iterator<decltype(*it)> out(cout, " ");
copy(v.begin(), v.end(), out);
cout << endl;
}
int main()
{//测试代码
IST ilst{ 1,5,7,6,2,4,8,9,3 }, ilst1{ 10,20,30 }, ilst2{ 300,200,100 };
Show(ilst);//输出内容1 5 7 6 2 4 8 9 3
ilst.reverse();//颠倒顺序输出
Show(ilst);//输出内容3 9 8 4 2 6 7 5 1
ilst.sort();//按从小到大排序
Show(ilst);//输出内容1 2 3 4 5 6 7 8 9
ilst.merge(ilst1);//默认谓词<从小到大顺序才能合并
Show(ilst);//输出内容1 2 3 4 5 6 7 8 9 10 20 30
auto f = [](int a, int b) {return a > b; };
ilst.sort(f);//从大到小排序
Show(ilst);//输出内容30 20 10 9 8 7 6 5 4 3 2 1
ilst.merge(ilst2,f);
Show(ilst);//输出内容300 200 100 30 20 10 9 8 7 6 5 4 3 2 1
ilst.remove(300);//删除300
ilst.remove_if([](int i) {return i == 200; });//删除元素中为200的
Show(ilst); //输出内容100 30 20 10 9 8 7 6 5 4 3 2 1
ilst.push_front(100);//开头插入一个元素100
Show(ilst);//输出内容100 100 30 20 10 9 8 7 6 5 4 3 2 1
ilst.unique();//调用erase删除同一个值重复的内容
Show(ilst);//输出内容100 30 20 10 9 8 7 6 5 4 3 2 1
ilst.push_back(1);//末尾插入一个元素,值为1
Show(ilst);//输出内容100 30 20 10 9 8 7 6 5 4 3 2 1 1
ilst.unique([](int i,int j) {return i == j; });//删除连续为1
Show(ilst);//输出内容 100 30 20 10 9 8 7 6 5 4 3 2 1
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>//inserter所在头文件
#include <functional>
using namespace std;
list<int>::iterator Ret(list<int>& v, int locat)
{
list<int>::iterator it = v.begin();
for (size_t i = 1; i != locat && i < v.size(); ++i)
++it;
return it;//返回当前迭代器位置
}
void Show(list<int>& v)
{
for (auto i : v)
cout << i << " ";
cout<<endl;
}
int main()
{//测试代码
list <int> lst = { 1,2,3,4,5 };
Show(lst);//输出内容1 2 3 4 5
list<int> lst2 = { 10,20 };
lst.splice(lst.begin(), lst2);//将lst2元素移动到lst首元素之前,并清除lst2里的元素
Show(lst);//输出内容10 20 1 2 3 4 5
list<int> lst3 = { 35,30,25,20,15,10,5,0 };
lst.splice(lst.end(), lst3, Ret(lst3,3));//把25移动到lst末尾
Show(lst);//输出内容10 20 1 2 3 4 5 25
lst.splice(lst.end(), lst3, lst3.begin(), lst3.end());//把lst3的元素移动到lst末尾
Show(lst);//输出内容10 20 1 2 3 4 5 25 35 30 20 15 10 5 0
system("pause");
return 0;
}
=====================================================================
//QQ108201645编写
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>//inserter所在头文件
#include <functional>
using namespace std;
void Show(list<string>& v)
{
for (auto i : v)
cout << i << " ";
cout<<endl;
}
int main()
{
/*练习10.42:使用 list 代替 vector 重新实现10.2.3节中的去除重复单词的程序。*/
list <string> lst = { "the", "quick", "red",
"fox", "jumps", "over", "the", "slow", "red", "turtle" };
lst.sort();//从小到大排序
Show(lst);//输出内容fox jumps over quick red red slow the the turtle
lst.unique([](string& s,string& s1) {return s == s1; });//删除重复的
Show(lst);//输出内容fox jumps over quick red slow the turtle
system("pause");
return 0;
}
―――――――――――――――――――――――――――――――――――――――